From 8f44607956d9f5dd6583bed5d5e8263d1f02440c Mon Sep 17 00:00:00 2001
From: Dessalines <tyhou13@gmx.com>
Date: Mon, 7 Sep 2020 23:09:11 -0500
Subject: [PATCH] Main page done.

---
 package.json                                  |   2 +-
 src/shared/components/data-type-select.tsx    |   1 -
 src/shared/components/listing-type-select.tsx |  18 ++
 src/shared/components/main.tsx                | 203 +++++++++++-------
 src/shared/components/navbar.tsx              |   1 -
 src/shared/components/sort-select.tsx         |   8 +-
 src/shared/routes.ts                          |   8 +-
 src/shared/utils.ts                           |  56 ++---
 yarn.lock                                     |   8 +-
 9 files changed, 190 insertions(+), 115 deletions(-)

diff --git a/package.json b/package.json
index 137e4cc..4ddde80 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.8",
+    "lemmy-js-client": "^1.0.9",
     "lint-staged": "^10.1.3",
     "mini-css-extract-plugin": "^0.11.0",
     "node-sass": "^4.12.0",
diff --git a/src/shared/components/data-type-select.tsx b/src/shared/components/data-type-select.tsx
index 06285f7..c3e1fc6 100644
--- a/src/shared/components/data-type-select.tsx
+++ b/src/shared/components/data-type-select.tsx
@@ -23,7 +23,6 @@ export class DataTypeSelect extends Component<
   constructor(props: any, context: any) {
     super(props, context);
     this.state = this.emptyState;
-    console.log(this.state);
   }
 
   static getDerivedStateFromProps(props: any): DataTypeSelectProps {
diff --git a/src/shared/components/listing-type-select.tsx b/src/shared/components/listing-type-select.tsx
index 3d12d43..f7d8cc3 100644
--- a/src/shared/components/listing-type-select.tsx
+++ b/src/shared/components/listing-type-select.tsx
@@ -6,6 +6,7 @@ import { i18n } from '../i18next';
 
 interface ListingTypeSelectProps {
   type_: ListingType;
+  showLocal?: boolean;
   onChange?(val: ListingType): any;
 }
 
@@ -31,6 +32,7 @@ export class ListingTypeSelect extends Component<
   static getDerivedStateFromProps(props: any): ListingTypeSelectProps {
     return {
       type_: props.type_,
+      showLocal: props.showLocal,
     };
   }
 
@@ -53,6 +55,22 @@ export class ListingTypeSelect extends Component<
           />
           {i18n.t('subscribed')}
         </label>
+        {this.props.showLocal && (
+          <label
+            className={`pointer btn btn-outline-secondary ${
+              this.state.type_ == ListingType.Local && 'active'
+            }`}
+          >
+            <input
+              id={`${this.id}-local`}
+              type="radio"
+              value={ListingType.Local}
+              checked={this.state.type_ == ListingType.Local}
+              onChange={linkEvent(this, this.handleTypeChange)}
+            />
+            {i18n.t('local')}
+          </label>
+        )}
         <label
           className={`pointer btn btn-outline-secondary ${
             this.state.type_ == ListingType.All && 'active'
diff --git a/src/shared/components/main.tsx b/src/shared/components/main.tsx
index 547e4c8..2cf434f 100644
--- a/src/shared/components/main.tsx
+++ b/src/shared/components/main.tsx
@@ -2,7 +2,6 @@ import { Component, linkEvent } from 'inferno';
 import { Helmet } from 'inferno-helmet';
 import { Link } from 'inferno-router';
 import { Subscription } from 'rxjs';
-import { retryWhen, delay, take } from 'rxjs/operators';
 import {
   UserOperation,
   CommunityUser,
@@ -56,7 +55,11 @@ import {
   setupTippy,
   favIconUrl,
   notifyPost,
+  setIsoData,
+  wsSubscribe,
   isBrowser,
+  setAuth,
+  lemmyHttp,
 } from '../utils';
 import { i18n } from '../i18next';
 import { T } from 'inferno-i18next';
@@ -90,34 +93,12 @@ interface UrlParams {
 }
 
 export class Main extends Component<any, MainState> {
+  private isoData = setIsoData(this.context);
   private subscription: Subscription;
   private emptyState: MainState = {
     subscribedCommunities: [],
     trendingCommunities: [],
-    siteRes: {
-      site: {
-        id: null,
-        name: null,
-        creator_id: null,
-        creator_name: null,
-        published: null,
-        number_of_users: null,
-        number_of_posts: null,
-        number_of_comments: null,
-        number_of_communities: null,
-        enable_downvotes: null,
-        open_registration: null,
-        enable_nsfw: null,
-        icon: null,
-        banner: null,
-        creator_preferred_username: null,
-      },
-      admins: [],
-      banned: [],
-      online: null,
-      version: null,
-      federated_instances: null,
-    },
+    siteRes: this.isoData.site,
     showEditSite: false,
     loading: true,
     posts: [],
@@ -137,59 +118,126 @@ export class Main extends Component<any, MainState> {
     this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
     this.handleDataTypeChange = this.handleDataTypeChange.bind(this);
 
-    if (isBrowser()) {
-      // TODO
-      /* 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') */
-      /* ); */
-      /* WebSocketService.Instance.getSite(); */
-      /* if (UserService.Instance.user) { */
-      /*   WebSocketService.Instance.getFollowedCommunities(); */
-      /* } */
-      /* let listCommunitiesForm: ListCommunitiesForm = { */
-      /*   sort: SortType.Hot, */
-      /*   limit: 6, */
-      /* }; */
-      /* WebSocketService.Instance.listCommunities(listCommunitiesForm); */
-      /* this.fetchData(); */
+    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) {
+      if (this.state.dataType == DataType.Post) {
+        this.state.posts = this.isoData.routeData[0].posts;
+      } else {
+        this.state.comments = this.isoData.routeData[0].comments;
+      }
+      this.state.trendingCommunities = this.isoData.routeData[1].communities;
+      if (UserService.Instance.user) {
+        this.state.subscribedCommunities = this.isoData.routeData[2].communities;
+      }
+      this.state.loading = false;
+    } else {
+      this.fetchTrendingCommunities();
+      this.fetchData();
+      if (UserService.Instance.user) {
+        WebSocketService.Instance.getFollowedCommunities();
+      }
     }
+
+    setupTippy();
+  }
+
+  fetchTrendingCommunities() {
+    let listCommunitiesForm: ListCommunitiesForm = {
+      sort: SortType.Hot,
+      limit: 6,
+    };
+    WebSocketService.Instance.listCommunities(listCommunitiesForm);
   }
 
   componentWillUnmount() {
-    this.subscription.unsubscribe();
-  }
-
-  /* static getDerivedStateFromProps(props: any): MainProps { */
-  /*   return { */
-  /*     listingType: getListingTypeFromProps(props), */
-  /*     dataType: getDataTypeFromProps(props), */
-  /*     sort: getSortTypeFromProps(props), */
-  /*     page: getPageFromProps(props), */
-  /*   }; */
-  /* } */
-
-  /* componentDidUpdate(_: any, lastState: MainState) { */
-  /*   if ( */
-  /*     lastState.listingType !== this.state.listingType || */
-  /*     lastState.dataType !== this.state.dataType || */
-  /*     lastState.sort !== this.state.sort || */
-  /*     lastState.page !== this.state.page */
-  /*   ) { */
-  /*     this.setState({ loading: true }); */
-  /*     this.fetchData(); */
-  /*   } */
-  /* } */
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
+  }
 
-  get documentTitle(): string {
-    if (this.state.siteRes.site.name) {
-      return `${this.state.siteRes.site.name}`;
+  static getDerivedStateFromProps(props: any): MainProps {
+    return {
+      listingType: getListingTypeFromProps(props),
+      dataType: getDataTypeFromProps(props),
+      sort: getSortTypeFromProps(props),
+      page: getPageFromProps(props),
+    };
+  }
+
+  static fetchInitialData(auth: string, path: string): Promise<any>[] {
+    let pathSplit = path.split('/');
+    let dataType: DataType = pathSplit[3]
+      ? DataType[pathSplit[3]]
+      : DataType.Post;
+
+    // TODO figure out auth default_listingType, default_sort_type
+    let type_: ListingType = pathSplit[5]
+      ? ListingType[pathSplit[5]]
+      : UserService.Instance.user
+      ? Object.values(ListingType)[
+          UserService.Instance.user.default_listing_type
+        ]
+      : ListingType.All;
+    let sort: SortType = pathSplit[7]
+      ? SortType[pathSplit[7]]
+      : UserService.Instance.user
+      ? Object.values(SortType)[UserService.Instance.user.default_sort_type]
+      : SortType.Active;
+
+    let page = pathSplit[9] ? Number(pathSplit[9]) : 1;
+
+    let promises: Promise<any>[] = [];
+
+    if (dataType == DataType.Post) {
+      let getPostsForm: GetPostsForm = {
+        page,
+        limit: fetchLimit,
+        sort,
+        type_,
+      };
+      setAuth(getPostsForm, auth);
+      promises.push(lemmyHttp.getPosts(getPostsForm));
     } else {
-      return 'Lemmy';
+      let getCommentsForm: GetCommentsForm = {
+        page,
+        limit: fetchLimit,
+        sort,
+        type_,
+      };
+      setAuth(getCommentsForm, auth);
+      promises.push(lemmyHttp.getComments(getCommentsForm));
     }
+
+    let trendingCommunitiesForm: ListCommunitiesForm = {
+      sort: SortType.Hot,
+      limit: 6,
+    };
+    promises.push(lemmyHttp.listCommunities(trendingCommunitiesForm));
+
+    if (auth) {
+      promises.push(lemmyHttp.getFollowedCommunities({ auth }));
+    }
+
+    return promises;
+  }
+
+  componentDidUpdate(_: any, lastState: MainState) {
+    if (
+      lastState.listingType !== this.state.listingType ||
+      lastState.dataType !== this.state.dataType ||
+      lastState.sort !== this.state.sort ||
+      lastState.page !== this.state.page
+    ) {
+      this.setState({ loading: true });
+      this.fetchData();
+    }
+  }
+
+  get documentTitle(): string {
+    return `${this.state.siteRes.site.name}`;
   }
 
   get favIcon(): string {
@@ -201,7 +249,6 @@ export class Main extends Component<any, MainState> {
   render() {
     return (
       <div class="container">
-        <h1 className={`text-warning`}>u stink main</h1>
         <Helmet title={this.documentTitle}>
           <link
             id="favicon"
@@ -236,7 +283,7 @@ export class Main extends Component<any, MainState> {
               <div class="card-body">
                 {this.trendingCommunities()}
                 {this.createCommunityButton()}
-                {/*
+                {/* TODO
                 {this.subscribedCommunities()}
                 */}
               </div>
@@ -257,7 +304,7 @@ export class Main extends Component<any, MainState> {
 
   createCommunityButton() {
     return (
-      <Link class="btn btn-secondary btn-block" to="/create_community">
+      <Link className="btn btn-secondary btn-block" to="/create_community">
         {i18n.t('create_a_community')}
       </Link>
     );
@@ -269,7 +316,7 @@ export class Main extends Component<any, MainState> {
         <h5>
           <T i18nKey="trending_communities">
             #
-            <Link class="text-body" to="/communities">
+            <Link className="text-body" to="/communities">
               #
             </Link>
           </T>
@@ -293,7 +340,7 @@ export class Main extends Component<any, MainState> {
           <h5>
             <T i18nKey="subscribed_to_communities">
               #
-              <Link class="text-body" to="/communities">
+              <Link className="text-body" to="/communities">
                 #
               </Link>
             </T>
@@ -537,6 +584,10 @@ export class Main extends Component<any, MainState> {
         <span class="mr-3">
           <ListingTypeSelect
             type_={this.state.listingType}
+            showLocal={
+              this.state.siteRes.federated_instances &&
+              this.state.siteRes.federated_instances.length > 0
+            }
             onChange={this.handleListingTypeChange}
           />
         </span>
diff --git a/src/shared/components/navbar.tsx b/src/shared/components/navbar.tsx
index 56829b5..5c7c438 100644
--- a/src/shared/components/navbar.tsx
+++ b/src/shared/components/navbar.tsx
@@ -84,7 +84,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
     // The login
     // TODO this needs some work
     if (this.props.site.my_user) {
-      console.log(this.props.site.my_user);
       UserService.Instance.user = this.props.site.my_user;
       // i18n.changeLanguage(getLanguage());
 
diff --git a/src/shared/components/sort-select.tsx b/src/shared/components/sort-select.tsx
index 1f0fb05..7ba8a5f 100644
--- a/src/shared/components/sort-select.tsx
+++ b/src/shared/components/sort-select.tsx
@@ -42,10 +42,10 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
         >
           <option disabled>{i18n.t('sort_type')}</option>
           {!this.props.hideHot && (
-            <>
-              <option value={SortType.Active}>{i18n.t('active')}</option>
-              <option value={SortType.Hot}>{i18n.t('hot')}</option>
-            </>
+            <option value={SortType.Hot}>{i18n.t('hot')}</option>
+          )}
+          {!this.props.hideHot && (
+            <option value={SortType.Active}>{i18n.t('active')}</option>
           )}
           <option value={SortType.New}>{i18n.t('new')}</option>
           <option disabled>─────</option>
diff --git a/src/shared/routes.ts b/src/shared/routes.ts
index 2b3eb75..1b43eda 100644
--- a/src/shared/routes.ts
+++ b/src/shared/routes.ts
@@ -22,10 +22,16 @@ interface IRoutePropsWithFetch extends IRouteProps {
 }
 
 export const routes: IRoutePropsWithFetch[] = [
-  { exact: true, path: `/`, component: Main },
+  {
+    exact: true,
+    path: `/`,
+    component: Main,
+    fetchInitialData: (auth, path) => Main.fetchInitialData(auth, path),
+  },
   {
     path: `/home/data_type/:data_type/listing_type/:listing_type/sort/:sort/page/:page`,
     component: Main,
+    fetchInitialData: (auth, path) => Main.fetchInitialData(auth, path),
   },
   { path: `/login`, component: Login },
   {
diff --git a/src/shared/utils.ts b/src/shared/utils.ts
index 315b0e9..3617fb6 100644
--- a/src/shared/utils.ts
+++ b/src/shared/utils.ts
@@ -25,6 +25,7 @@ import 'moment/locale/sq';
 import 'moment/locale/km';
 import 'moment/locale/ga';
 import 'moment/locale/sr';
+import 'moment/locale/ko';
 
 import {
   UserOperation,
@@ -96,6 +97,7 @@ export const languages = [
   { code: 'gl', name: 'Galego' },
   { code: 'hu', name: 'Magyar Nyelv' },
   { code: 'ka', name: 'ქართული ენა' },
+  { code: 'ko', name: '한국어' },
   { code: 'km', name: 'ភាសាខ្មែរ' },
   { code: 'hi', name: 'मानक हिन्दी' },
   { code: 'fa', name: 'فارسی' },
@@ -428,6 +430,8 @@ export function getMomentLanguage(): string {
     lang = 'ga';
   } else if (lang.startsWith('sr')) {
     lang = 'sr';
+  } else if (lang.startsWith('ko')) {
+    lang = 'ko';
   } else {
     lang = 'en';
   }
@@ -718,16 +722,20 @@ export function setupTribute() {
   });
 }
 
-// TODO
-// let tippyInstance = tippy('[data-tippy-content]');
+var tippyInstance;
+if (isBrowser()) {
+  tippyInstance = tippy('[data-tippy-content]');
+}
 
 export function setupTippy() {
-  // tippyInstance.forEach(e => e.destroy());
-  // tippyInstance = tippy('[data-tippy-content]', {
-  //   delay: [500, 0],
-  //   // Display on "long press"
-  //   touch: ['hold', 500],
-  // });
+  if (isBrowser()) {
+    tippyInstance.forEach(e => e.destroy());
+    tippyInstance = tippy('[data-tippy-content]', {
+      delay: [500, 0],
+      // Display on "long press"
+      touch: ['hold', 500],
+    });
+  }
 }
 
 function userSearch(text: string, cb: any) {
@@ -805,32 +813,26 @@ function communitySearch(text: string, cb: any) {
 }
 
 export function getListingTypeFromProps(props: any): ListingType {
-  // TODO
-  return ListingType.All;
-  // return props.match.params.listing_type
-  //   ? routeListingTypeToEnum(props.match.params.listing_type)
-  //   : UserService.Instance.user
-  //   ? Object.values(ListingType)[UserService.Instance.user.default_listing_type]
-  //   : ListingType.All;
+  return props.match.params.listing_type
+    ? routeListingTypeToEnum(props.match.params.listing_type)
+    : UserService.Instance.user
+    ? Object.values(ListingType)[UserService.Instance.user.default_listing_type]
+    : ListingType.All;
 }
 
 // TODO might need to add a user setting for this too
 export function getDataTypeFromProps(props: any): DataType {
-  // TODO
-  return DataType.Post;
-  // return props.match.params.data_type
-  //   ? routeDataTypeToEnum(props.match.params.data_type)
-  //   : DataType.Post;
+  return props.match.params.data_type
+    ? routeDataTypeToEnum(props.match.params.data_type)
+    : DataType.Post;
 }
 
 export function getSortTypeFromProps(props: any): SortType {
-  // TODO
-  return SortType.Active;
-  // return props.match.params.sort
-  //   ? routeSortTypeToEnum(props.match.params.sort)
-  //   : UserService.Instance.user
-  //   ? Object.values(SortType)[UserService.Instance.user.default_sort_type]
-  //   : SortType.Active;
+  return props.match.params.sort
+    ? routeSortTypeToEnum(props.match.params.sort)
+    : UserService.Instance.user
+    ? Object.values(SortType)[UserService.Instance.user.default_sort_type]
+    : SortType.Active;
 }
 
 export function getPageFromProps(props: any): number {
diff --git a/yarn.lock b/yarn.lock
index d61a002..bd7f562 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.8:
-  version "1.0.8"
-  resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-1.0.8.tgz#98e34c8e3cd07427f883f60fad376dc4d6f46e7f"
-  integrity sha512-YZxD3+8RGz7cRKdI8EIe5iQqQIMm5WzdNz6zZ7/CdkMtXUv6YuMOEv8HLTvBoGuaWIJwlMJ+23NIarxlT26IEw==
+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==
 
 leven@^3.1.0:
   version "3.1.0"
-- 
2.44.1