]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/communities.tsx
Remove categories
[lemmy-ui.git] / src / shared / components / communities.tsx
index 2429599862887938406957e3b920ea21d751a35a..74a1ac32a27e3495cecfe5a225ca4e54e7b71d65 100644 (file)
@@ -1,39 +1,43 @@
-import { Component, linkEvent } from 'inferno';
-import { Helmet } from 'inferno-helmet';
-import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
+import { Component, linkEvent } from "inferno";
+import { HtmlTags } from "./html-tags";
+import { Subscription } from "rxjs";
 import {
   UserOperation,
-  Community,
+  CommunityView,
   ListCommunitiesResponse,
   CommunityResponse,
-  FollowCommunityForm,
-  ListCommunitiesForm,
+  FollowCommunity,
+  ListCommunities,
   SortType,
-  WebSocketJsonResponse,
-  GetSiteResponse,
-  Site,
-} from 'lemmy-js-client';
-import { WebSocketService } from '../services';
+  ListingType,
+  SiteView,
+} from "lemmy-js-client";
+import { WebSocketService } from "../services";
 import {
   wsJsonToRes,
   toast,
   getPageFromProps,
   isBrowser,
-  lemmyHttp,
-  setAuth,
-} from '../utils';
-import { CommunityLink } from './community-link';
-import { i18n } from '../i18next';
-import { IsoData } from 'shared/interfaces';
+  setIsoData,
+  wsSubscribe,
+  wsUserOp,
+  wsClient,
+  authField,
+  setOptionalAuth,
+} from "../utils";
+import { CommunityLink } from "./community-link";
+import { Spinner } from "./icon";
+import { i18n } from "../i18next";
+import { InitialFetchRequest } from "shared/interfaces";
 
 const communityLimit = 100;
 
 interface CommunitiesState {
-  communities: Community[];
+  communities: CommunityView[];
   page: number;
   loading: boolean;
-  site: Site;
+  site_view: SiteView;
+  searchText: string;
 }
 
 interface CommunitiesProps {
@@ -42,36 +46,28 @@ interface CommunitiesProps {
 
 export class Communities extends Component<any, CommunitiesState> {
   private subscription: Subscription;
+  private isoData = setIsoData(this.context);
   private emptyState: CommunitiesState = {
     communities: [],
     loading: true,
     page: getPageFromProps(this.props),
-    site: undefined,
+    site_view: this.isoData.site_res.site_view,
+    searchText: "",
   };
 
   constructor(props: any, context: any) {
     super(props, context);
     this.state = this.emptyState;
-    let isoData: IsoData;
 
-    if (isBrowser()) {
-      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')
-        );
-      isoData = window.isoData;
-    } else {
-      isoData = this.context.router.staticContext;
-    }
-
-    this.state.site = isoData.site.site;
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
 
     // Only fetch the data if coming from another route
-    if (isoData.path == this.context.router.route.match.path) {
-      this.state.communities = isoData.routeData[0].communities;
+    if (this.isoData.path == this.context.router.route.match.url) {
+      this.state.communities = this.isoData.routeData[0].communities;
+      this.state.communities.sort(
+        (a, b) => b.counts.subscribers - a.counts.subscribers
+      );
       this.state.loading = false;
     } else {
       this.refetch();
@@ -98,78 +94,85 @@ export class Communities extends Component<any, CommunitiesState> {
   }
 
   get documentTitle(): string {
-    if (this.state.site) {
-      return `${i18n.t('communities')} - ${this.state.site.name}`;
-    } else {
-      return 'Lemmy';
-    }
+    return `${i18n.t("communities")} - ${this.state.site_view.site.name}`;
   }
 
   render() {
     return (
       <div class="container">
-        <Helmet title={this.documentTitle} />
+        <HtmlTags
+          title={this.documentTitle}
+          path={this.context.router.route.match.url}
+        />
         {this.state.loading ? (
-          <h5 class="">
-            <svg class="icon icon-spinner spin">
-              <use xlinkHref="#icon-spinner"></use>
-            </svg>
+          <h5>
+            <Spinner />
           </h5>
         ) : (
           <div>
-            <h5>{i18n.t('list_of_communities')}</h5>
+            <div class="row">
+              <div class="col-md-6">
+                <h4>{i18n.t("list_of_communities")}</h4>
+              </div>
+              <div class="col-md-6">
+                <div class="float-md-right">{this.searchForm()}</div>
+              </div>
+            </div>
+
             <div class="table-responsive">
               <table id="community_table" class="table table-sm table-hover">
                 <thead class="pointer">
                   <tr>
-                    <th>{i18n.t('name')}</th>
-                    <th>{i18n.t('category')}</th>
-                    <th class="text-right">{i18n.t('subscribers')}</th>
+                    <th>{i18n.t("name")}</th>
+                    <th class="text-right">{i18n.t("subscribers")}</th>
+                    <th class="text-right">
+                      {i18n.t("users")} / {i18n.t("month")}
+                    </th>
                     <th class="text-right d-none d-lg-table-cell">
-                      {i18n.t('posts')}
+                      {i18n.t("posts")}
                     </th>
                     <th class="text-right d-none d-lg-table-cell">
-                      {i18n.t('comments')}
+                      {i18n.t("comments")}
                     </th>
                     <th></th>
                   </tr>
                 </thead>
                 <tbody>
-                  {this.state.communities.map(community => (
+                  {this.state.communities.map(cv => (
                     <tr>
                       <td>
-                        <CommunityLink community={community} />
-                      </td>
-                      <td>{community.category_name}</td>
-                      <td class="text-right">
-                        {community.number_of_subscribers}
+                        <CommunityLink community={cv.community} />
                       </td>
+                      <td class="text-right">{cv.counts.subscribers}</td>
+                      <td class="text-right">{cv.counts.users_active_month}</td>
                       <td class="text-right d-none d-lg-table-cell">
-                        {community.number_of_posts}
+                        {cv.counts.posts}
                       </td>
                       <td class="text-right d-none d-lg-table-cell">
-                        {community.number_of_comments}
+                        {cv.counts.comments}
                       </td>
                       <td class="text-right">
-                        {community.subscribed ? (
+                        {cv.subscribed ? (
                           <span
                             class="pointer btn-link"
+                            role="button"
                             onClick={linkEvent(
-                              community.id,
+                              cv.community.id,
                               this.handleUnsubscribe
                             )}
                           >
-                            {i18n.t('unsubscribe')}
+                            {i18n.t("unsubscribe")}
                           </span>
                         ) : (
                           <span
                             class="pointer btn-link"
+                            role="button"
                             onClick={linkEvent(
-                              community.id,
+                              cv.community.id,
                               this.handleSubscribe
                             )}
                           >
-                            {i18n.t('subscribe')}
+                            {i18n.t("subscribe")}
                           </span>
                         )}
                       </td>
@@ -185,6 +188,32 @@ export class Communities extends Component<any, CommunitiesState> {
     );
   }
 
+  searchForm() {
+    return (
+      <form
+        class="form-inline"
+        onSubmit={linkEvent(this, this.handleSearchSubmit)}
+      >
+        <input
+          type="text"
+          id="communities-search"
+          class="form-control mr-2 mb-2"
+          value={this.state.searchText}
+          placeholder={`${i18n.t("search")}...`}
+          onInput={linkEvent(this, this.handleSearchChange)}
+          required
+          minLength={3}
+        />
+        <label class="sr-only" htmlFor="communities-search">
+          {i18n.t("search")}
+        </label>
+        <button type="submit" class="btn btn-secondary mr-2 mb-2">
+          <span>{i18n.t("search")}</span>
+        </button>
+      </form>
+    );
+  }
+
   paginator() {
     return (
       <div class="mt-2">
@@ -193,7 +222,7 @@ export class Communities extends Component<any, CommunitiesState> {
             class="btn btn-secondary mr-1"
             onClick={linkEvent(this, this.prevPage)}
           >
-            {i18n.t('prev')}
+            {i18n.t("prev")}
           </button>
         )}
 
@@ -202,7 +231,7 @@ export class Communities extends Component<any, CommunitiesState> {
             class="btn btn-secondary"
             onClick={linkEvent(this, this.nextPage)}
           >
-            {i18n.t('next')}
+            {i18n.t("next")}
           </button>
         )}
       </div>
@@ -223,68 +252,83 @@ export class Communities extends Component<any, CommunitiesState> {
   }
 
   handleUnsubscribe(communityId: number) {
-    let form: FollowCommunityForm = {
+    let form: FollowCommunity = {
       community_id: communityId,
       follow: false,
+      auth: authField(),
     };
-    WebSocketService.Instance.followCommunity(form);
+    WebSocketService.Instance.send(wsClient.followCommunity(form));
   }
 
   handleSubscribe(communityId: number) {
-    let form: FollowCommunityForm = {
+    let form: FollowCommunity = {
       community_id: communityId,
       follow: true,
+      auth: authField(),
     };
-    WebSocketService.Instance.followCommunity(form);
+    WebSocketService.Instance.send(wsClient.followCommunity(form));
+  }
+
+  handleSearchChange(i: Communities, event: any) {
+    i.setState({ searchText: event.target.value });
+  }
+
+  handleSearchSubmit(i: Communities) {
+    const searchParamEncoded = encodeURIComponent(i.state.searchText);
+    i.context.router.history.push(
+      `/search/q/${searchParamEncoded}/type/Communities/sort/TopAll/page/1`
+    );
   }
 
   refetch() {
-    let listCommunitiesForm: ListCommunitiesForm = {
+    let listCommunitiesForm: ListCommunities = {
+      type_: ListingType.All,
       sort: SortType.TopAll,
       limit: communityLimit,
       page: this.state.page,
+      auth: authField(false),
     };
 
-    WebSocketService.Instance.listCommunities(listCommunitiesForm);
+    WebSocketService.Instance.send(
+      wsClient.listCommunities(listCommunitiesForm)
+    );
   }
 
-  static fetchInitialData(auth: string, path: string): Promise<any>[] {
-    let pathSplit = path.split('/');
-    let page = pathSplit[2] ? Number(pathSplit[2]) : 1;
-    let listCommunitiesForm: ListCommunitiesForm = {
+  static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
+    let pathSplit = req.path.split("/");
+    let page = pathSplit[3] ? Number(pathSplit[3]) : 1;
+    let listCommunitiesForm: ListCommunities = {
+      type_: ListingType.All,
       sort: SortType.TopAll,
       limit: communityLimit,
       page,
     };
-    setAuth(listCommunitiesForm, auth);
+    setOptionalAuth(listCommunitiesForm, req.auth);
 
-    return [lemmyHttp.listCommunities(listCommunitiesForm)];
+    return [req.client.listCommunities(listCommunitiesForm)];
   }
 
-  parseMessage(msg: WebSocketJsonResponse) {
-    console.log(msg);
-    let res = wsJsonToRes(msg);
+  parseMessage(msg: any) {
+    let op = wsUserOp(msg);
     if (msg.error) {
-      toast(i18n.t(msg.error), 'danger');
+      toast(i18n.t(msg.error), "danger");
       return;
-    } else if (res.op == UserOperation.ListCommunities) {
-      let data = res.data as ListCommunitiesResponse;
+    } else if (op == UserOperation.ListCommunities) {
+      let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
       this.state.communities = data.communities;
       this.state.communities.sort(
-        (a, b) => b.number_of_subscribers - a.number_of_subscribers
+        (a, b) => b.counts.subscribers - a.counts.subscribers
       );
       this.state.loading = false;
       window.scrollTo(0, 0);
       this.setState(this.state);
-    } else if (res.op == UserOperation.FollowCommunity) {
-      let data = res.data as CommunityResponse;
-      let found = this.state.communities.find(c => c.id == data.community.id);
-      found.subscribed = data.community.subscribed;
-      found.number_of_subscribers = data.community.number_of_subscribers;
-      this.setState(this.state);
-    } else if (res.op == UserOperation.GetSite) {
-      let data = res.data as GetSiteResponse;
-      this.state.site = data.site;
+    } else if (op == UserOperation.FollowCommunity) {
+      let data = wsJsonToRes<CommunityResponse>(msg).data;
+      let found = this.state.communities.find(
+        c => c.community.id == data.community_view.community.id
+      );
+      found.subscribed = data.community_view.subscribed;
+      found.counts.subscribers = data.community_view.counts.subscribers;
       this.setState(this.state);
     }
   }