diff --git a/src/components/communities.tsx b/src/components/communities.tsx index 97de07fd..a3a3071b 100644 --- a/src/components/communities.tsx +++ b/src/components/communities.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import React, { Component } from 'react'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; @@ -7,12 +8,11 @@ import { ListCommunitiesResponse, CommunityResponse, FollowCommunityForm, - ListCommunitiesForm, SortType, WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService } from '../services'; -import { wsJsonToRes, toast, getPageFromProps, siteName } from '../utils'; +import { wsJsonToRes, toast, getPageFromProps, siteName, api } from '../utils'; import { CommunityLink } from './community-link'; import { i18n } from '../i18next'; import { linkEvent } from '../linkEvent'; @@ -20,6 +20,7 @@ import { SpinnerSection } from './Spinner'; import Button from './elements/Button'; import { Heading } from 'theme-ui'; import Block from './elements/Block'; +import { AxiosError } from 'axios'; const communityLimit = 100; @@ -53,10 +54,10 @@ export class Communities extends Component { () => console.log('complete') ); - this.refetch(); + this.fetchCommunityList(); } - componentWillUnmount() { + componentWillUnmount(): void { this.subscription.unsubscribe(); } @@ -66,14 +67,14 @@ export class Communities extends Component { }; } - componentDidUpdate(_: any, lastState: CommunitiesState) { + componentDidUpdate(_: any, lastState: CommunitiesState): void { if (lastState.page !== this.state.page) { this.setState({ loading: true }); - this.refetch(); + this.fetchCommunityList(); } } - render() { + render(): JSX.Element { const { subscribed, notSubscribed } = this.state.communities.reduce( (result, community) => { if (community.subscribed) { @@ -89,7 +90,6 @@ export class Communities extends Component { } ); - // console.log({ combinedCommunities }); return (
{this.state.loading ? ( @@ -148,12 +148,7 @@ export class Communities extends Component { {community.title} - - {/* - {i18n.t('category')}: - */} - {community.category_name} - + {community.category_name} {community.number_of_subscribers}{' '} {i18n.t('subscribers')} @@ -172,36 +167,6 @@ export class Communities extends Component { ); })} - {/* {this.state.communities} */} - {/*
- - - - {i18n.t('name')} - - {i18n.t('title')} - - {i18n.t('category')} - {i18n.t('subscribers')} - - {i18n.t('posts')} - - - {i18n.t('comments')} - - - - - - - - -
*/} {this.paginator()}
)} @@ -209,7 +174,7 @@ export class Communities extends Component { ); } - paginator() { + paginator(): JSX.Element { return (
{this.state.page > 1 && ( @@ -233,20 +198,20 @@ export class Communities extends Component { ); } - updateUrl(paramUpdates: CommunitiesProps) { + updateUrl(paramUpdates: CommunitiesProps): void { const page = paramUpdates.page || this.state.page; this.props.history.push(`/communities/page/${page}`); } - nextPage(i: Communities) { + nextPage(i: Communities): void { i.updateUrl({ page: i.state.page + 1 }); } - prevPage(i: Communities) { + prevPage(i: Communities): void { i.updateUrl({ page: i.state.page - 1 }); } - handleUnsubscribe(communityId: number) { + handleUnsubscribe(communityId: number): void { let form: FollowCommunityForm = { community_id: communityId, follow: false, @@ -254,7 +219,7 @@ export class Communities extends Component { WebSocketService.Instance.followCommunity(form); } - handleSubscribe(communityId: number) { + handleSubscribe(communityId: number): void { let form: FollowCommunityForm = { community_id: communityId, follow: true, @@ -262,38 +227,48 @@ export class Communities extends Component { WebSocketService.Instance.followCommunity(form); } - refetch() { - let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.TopAll], + async fetchCommunityList(): Promise { + const params = new URLSearchParams({ + sort: SortType[SortType.New], limit: communityLimit, page: this.state.page, - }; + } as any); - WebSocketService.Instance.listCommunities(listCommunitiesForm); + api + .get(`community/list?${params.toString()}`) + .then(res => { + const data = res.data; + this.setState( + { + communities: data.communities.sort( + (a, b) => b.number_of_subscribers - a.number_of_subscribers + ), + loading: false, + }, + () => { + window.scrollTo(0, 0); + // XXX: Sort this table? + let table = document.querySelector('#community_table'); + return table; + } + ); + }) + .catch((err: Error | AxiosError) => { + const res = (err as AxiosError).response; + if (res) { + const data = res.data as { error: string }; + toast(i18n.t(data.error), 'danger'); + } else { + console.log(err); + } + }); } parseMessage(msg: WebSocketJsonResponse) { - console.log(msg); let res = wsJsonToRes(msg); if (msg.error) { toast(i18n.t(msg.error), 'danger'); return; - } else if (res.op == UserOperation.ListCommunities) { - let data = res.data as ListCommunitiesResponse; - this.setState( - { - communities: data.communities.sort( - (a, b) => b.number_of_subscribers - a.number_of_subscribers - ), - loading: false, - }, - () => { - window.scrollTo(0, 0); - // XXX: Sort this table? - let table = document.querySelector('#community_table'); - return table; - } - ); } else if (res.op == UserOperation.FollowCommunity) { let data = res.data as CommunityResponse; let found = this.state.communities.find(c => c.id == data.community.id); diff --git a/src/components/main.tsx b/src/components/main.tsx index f75ee4ce..00abfb90 100644 --- a/src/components/main.tsx +++ b/src/components/main.tsx @@ -9,14 +9,12 @@ import { UserOperation, CommunityUser, GetFollowedCommunitiesResponse, - ListCommunitiesForm, ListCommunitiesResponse, Community, SortType, GetSiteResponse, ListingType, DataType, - GetPostsResponse, PostResponse, Post, Comment, @@ -61,6 +59,7 @@ import { getRandomTagline, getMoscowTime, siteName, + api, } from '../utils'; import { BASE_PATH } from '../isProduction'; import { i18n } from '../i18next'; @@ -79,6 +78,7 @@ import Tooltip from './Tooltip'; import Header, { Separator } from './Header'; import { siteSubject } from '../services/SiteService'; import FeaturedPosts from './FeaturedPosts'; +import { AxiosError } from 'axios'; interface MainState { subscribedCommunities: Array; @@ -189,11 +189,6 @@ class Main extends Component { if (UserService.Instance.user) { WebSocketService.Instance.getFollowedCommunities(); } - let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.Hot], - limit: 6, - }; - WebSocketService.Instance.listCommunities(listCommunitiesForm); this.fetchData(); } @@ -738,10 +733,35 @@ class Main extends Component { }; WebSocketService.Instance.getComments(getCommentsForm); } + + this.fetchCommunityList(); + } + + async fetchCommunityList() { + const params = new URLSearchParams({ + sort: SortType[SortType.Hot], + limit: 6, + } as any); + + api + .get(`community/list?${params.toString()}`) + .then(res => { + this.setState({ + trendingCommunities: res.data.communities, + }); + }) + .catch((err: Error | AxiosError) => { + const res = (err as AxiosError).response; + if (res) { + const data = res.data as { error: string }; + toast(i18n.t(data.error), 'danger'); + } else { + console.log(err); + } + }); } parseMessage(msg: WebSocketJsonResponse) { - console.log(msg); let res = wsJsonToRes(msg); if (msg.error) { toast(i18n.t(msg.error), 'danger'); @@ -753,11 +773,6 @@ class Main extends Component { this.setState({ subscribedCommunities: data.communities, }); - } else if (res.op === UserOperation.ListCommunities) { - let data = res.data as ListCommunitiesResponse; - this.setState({ - trendingCommunities: data.communities, - }); } else if (res.op === UserOperation.CreatePost) { let data = res.data as PostResponse; diff --git a/src/components/post-form.tsx b/src/components/post-form.tsx index 3db12204..99d9ccc5 100644 --- a/src/components/post-form.tsx +++ b/src/components/post-form.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import React, { Component, useState } from 'react'; import { Prompt } from 'react-router-dom'; import { PostListings } from './post-listings'; @@ -35,6 +36,7 @@ import { pictrsDeleteToast, validTitle, isPostChanged, + api, } from '../utils'; import { i18n } from '../i18next'; import { cleanURL } from '../clean-url'; @@ -51,6 +53,7 @@ import { } from '@reach/combobox'; import '@reach/combobox/styles.css'; import { Alert, Button, Input, Textarea } from 'theme-ui'; +import { AxiosError } from 'axios'; export const MAX_POST_TITLE_LENGTH = 160; export const MAX_POST_BODY_LENGTH = 20000; @@ -219,7 +222,7 @@ export class PostForm extends Component { this.handlePostBodyChange = this.handlePostBodyChange.bind(this); } - componentDidMount() { + componentDidMount(): void { if (this.props.post) { this.state.postForm = { body: this.props.post.body, @@ -260,17 +263,11 @@ export class PostForm extends Component { () => console.log('complete') ); - let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.TopAll], - limit: 9999, - }; - - WebSocketService.Instance.listCommunities(listCommunitiesForm); - + this.fetchCommunityList(); setupTippy(); } - componentDidUpdate() { + componentDidUpdate(): void { if ( !this.state.loading && (this.state.postForm.name || @@ -283,13 +280,13 @@ export class PostForm extends Component { } } - componentWillUnmount() { + componentWillUnmount(): void { // this.choices && this.choices.destroy(); this.subscription.unsubscribe(); window.onbeforeunload = null; } - render() { + render(): JSX.Element { const postTitleBlank = this.state.postForm.name === null || this.state.postForm.name.trim() === ''; @@ -340,6 +337,7 @@ export class PostForm extends Component {
{i18n.t('copy_suggested_title', { title: this.state.suggestedTitle, @@ -467,35 +465,6 @@ export class PostForm extends Component { {i18n.t('community')}
- {/* */} { ); } - handlePostSubmit(i: PostForm, event: any) { + handlePostSubmit(i: PostForm, event: any): void { event.preventDefault(); // make sure post title is not just whitespace @@ -588,7 +557,7 @@ export class PostForm extends Component { i.setState(i.state); } - copySuggestedTitle(i: PostForm) { + copySuggestedTitle(i: PostForm): void { i.state.postForm.name = i.state.suggestedTitle.substring( 0, MAX_POST_TITLE_LENGTH @@ -597,15 +566,15 @@ export class PostForm extends Component { i.setState(i.state); } - handlePostUrlChange = (event: any) => { + handlePostUrlChange = (event: any): void => { // i.state.postForm.url = event.target.value; - this.setState({ - postForm: { ...this.state.postForm, url: event.target.value }, - }); + this.setState(prev => ({ + postForm: { ...prev.postForm, url: event.target.value }, + })); this.fetchPageTitle(); }; - async fetchPageTitle() { + async fetchPageTitle(): Promise { if (validURL(this.state.postForm.url)) { let form: SearchForm = { q: this.state.postForm.url, @@ -620,23 +589,19 @@ export class PostForm extends Component { // Fetch the page title const title = await getPageTitle(this.state.postForm.url); if (title !== null) { - this.state.suggestedTitle = title; - this.setState(this.state); + this.setState({ suggestedTitle: title }); } } else { - this.state.suggestedTitle = undefined; - this.state.crossPosts = []; + this.setState({ suggestedTitle: undefined, crossPosts: [] }); } } - handlePostNameChange(i: PostForm, event: any) { - let spooked = event.target.value.replace('hexbear', 'hexedbear'); - i.state.postForm.name = spooked; + handlePostNameChange(i: PostForm): void { i.setState(i.state); i.fetchSimilarPosts(); } - fetchSimilarPosts() { + fetchSimilarPosts(): void { let form: SearchForm = { q: this.state.postForm.name, type_: SearchType[SearchType.Posts], @@ -649,43 +614,40 @@ export class PostForm extends Component { if (this.state.postForm.name !== '') { WebSocketService.Instance.search(form); } else { - this.state.suggestedPosts = []; + this.setState({ suggestedPosts: [] }); } - - this.setState(this.state); } - handlePostBodyChange = (val: string) => { - this.setState({ postForm: { ...this.state.postForm, body: val } }); + handlePostBodyChange = (val: string): void => { + this.setState(prev => ({ postForm: { ...prev.postForm, body: val } })); }; - handlePostCommunityChange = (community_id: number) => { - this.setState({ postForm: { ...this.state.postForm, community_id } }); + handlePostCommunityChange = (community_id: number): void => { + this.setState(prev => ({ postForm: { ...prev.postForm, community_id } })); }; - handlePostNsfwChange(i: PostForm, event: any) { + handlePostNsfwChange(i: PostForm, event: any): void { i.state.postForm.nsfw = event.target.checked; i.setState(i.state); } - handleCancel(i: PostForm) { + handleCancel(i: PostForm): void { i.props.onCancel(); } - handlePreviewToggle(i: PostForm, event: any) { + handlePreviewToggle(i: PostForm, event: any): void { event.preventDefault(); i.state.previewMode = !i.state.previewMode; i.setState(i.state); } - handleImageUploadPaste(i: PostForm, event: any) { - console.log('PASTING'); + handleImageUploadPaste(i: PostForm, event: any): void { let image = event.clipboardData.files[0]; if (image) { i.handleImageUpload(i, image); } } - handleImageUpload(i: PostForm, event: any) { + handleImageUpload(i: PostForm, event: any): void { let file: any; if (event.target) { event.preventDefault(); @@ -735,105 +697,78 @@ export class PostForm extends Component { }); } - // initChoices = (selectId: any) => { - // setTimeout(() => { - // this.choices = new Choices(selectId, { - // shouldSort: false, - // classNames: { - // containerOuter: 'choices', - // containerInner: 'choices__inner bg-secondary border-0', - // input: 'form-control', - // inputCloned: 'choices__input--cloned', - // list: 'choices__list', - // listItems: 'choices__list--multiple', - // listSingle: 'choices__list--single', - // listDropdown: 'choices__list--dropdown', - // item: 'choices__item bg-secondary', - // itemSelectable: 'choices__item--selectable', - // itemDisabled: 'choices__item--disabled', - // itemChoice: 'choices__item--choice', - // placeholder: 'choices__placeholder', - // group: 'choices__group', - // groupHeading: 'choices__heading', - // button: 'choices__button', - // activeState: 'is-active', - // focusState: 'is-focused', - // openState: 'is-open', - // disabledState: 'is-disabled', - // highlightedState: 'text-info', - // selectedState: 'text-info', - // flippedState: 'is-flipped', - // loadingState: 'is-loading', - // noResults: 'has-no-results', - // noChoices: 'has-no-choices', - // }, - // }); - // this.choices.passedElement.element.addEventListener( - // 'choice', - // (e: any) => { - // this.setState({ postForm: { ...this.state.postForm, community_id: Number(e.detail.choice.value) } }); - // }, - // false - // ); - // }, 10) - // } - - parseMessage(msg: WebSocketJsonResponse) { + async fetchCommunityList(): Promise { + const params = new URLSearchParams({ + sort: SortType[SortType.Hot], + limit: 9999, + } as any); + + api + .get(`community/list?${params.toString()}`) + .then(res => { + const data = res.data; + this.setState( + { + communities: data.communities, + }, + () => { + if (this.props.post) { + this.setState(prev => ({ + postForm: { + ...prev.postForm, + community_id: this.props.post.community_id, + }, + })); + } else if (this.props.params && this.props.params.community) { + let foundCommunityId = data.communities.find( + r => r.name == this.props.params.community + ).id; + this.setState(prev => ({ + postForm: { ...prev.postForm, community_id: foundCommunityId }, + })); + } else { + // By default, the null valued 'Select a Community' + } + } + ); + }) + .catch((err: Error | AxiosError) => { + const res = (err as AxiosError).response; + if (res) { + const data = res.data as { error: string }; + toast(i18n.t(data.error), 'danger'); + } else { + console.log(err); + } + }); + } + + parseMessage(msg: WebSocketJsonResponse): void { let res = wsJsonToRes(msg); if (msg.error) { toast(i18n.t(msg.error), 'danger'); - this.state.loading = false; - this.setState(this.state); + this.setState({ loading: false }); return; - } else if (res.op == UserOperation.ListCommunities) { - let data = res.data as ListCommunitiesResponse; - // this.state.communities = data.communities; - this.setState({ communities: data.communities }); - if (this.props.post) { - this.setState({ - postForm: { - ...this.state.postForm, - community_id: this.props.post.community_id, - }, - }); - } else if (this.props.params && this.props.params.community) { - let foundCommunityId = data.communities.find( - r => r.name == this.props.params.community - ).id; - this.setState({ - postForm: { ...this.state.postForm, community_id: foundCommunityId }, - }); - } else { - // By default, the null valued 'Select a Community' - } - // this.setState(this.state); - - // Set up select searching - let selectId = document.getElementById('post-community'); - if (selectId) { - // this.initChoices(selectId); - } } else if (res.op == UserOperation.CreatePost) { let data = res.data as PostResponse; if (data.post.creator_id == UserService.Instance.user.id) { - this.state.loading = false; + this.setState({ loading: false }); this.props.onCreate(data.post.id); } } else if (isPostChanged(res.op)) { let data = res.data as PostResponse; if (data.post.creator_id == UserService.Instance.user.id) { - this.state.loading = false; + this.setState({ loading: false }); this.props.onEdit(data.post); } } else if (res.op == UserOperation.Search) { let data = res.data as SearchResponse; if (data.type_ == SearchType[SearchType.Posts]) { - this.state.suggestedPosts = data.posts; + this.setState({ suggestedPosts: data.posts }); } else if (data.type_ == SearchType[SearchType.Url]) { - this.state.crossPosts = data.posts; + this.setState({ crossPosts: data.posts }); } - this.setState(this.state); } } } diff --git a/src/interfaces.ts b/src/interfaces.ts index b6853c9e..f32ebf90 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -3,7 +3,6 @@ export enum UserOperation { Register, CreateCommunity, CreatePost, - ListCommunities, ListCategories, GetCommunity, CreateComment, diff --git a/src/services/WebSocketService.ts b/src/services/WebSocketService.ts index 012cb946..945247e6 100644 --- a/src/services/WebSocketService.ts +++ b/src/services/WebSocketService.ts @@ -14,7 +14,6 @@ import { GetCommunityForm, FollowCommunityForm, GetFollowedCommunitiesForm, - ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, @@ -171,11 +170,6 @@ export class WebSocketService { ); } - public listCommunities(form: ListCommunitiesForm) { - this.setAuth(form, false); - this.ws.send(this.wsSendWrapper(UserOperation.ListCommunities, form)); - } - public getFollowedCommunities() { let form: GetFollowedCommunitiesForm = { auth: UserService.Instance.auth }; this.ws.send(