]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/home/home.tsx
Fix home page not using site-level listing type #1612 (#1778)
[lemmy-ui.git] / src / shared / components / home / home.tsx
index 4f9b9694cf501d857fdb6ba978d174294d6d7f1c..741dfa57aa7576eb0138bf1d687ab2773ae4a70d 100644 (file)
@@ -1,5 +1,29 @@
+import {
+  commentsToFlatNodes,
+  editComment,
+  editPost,
+  editWith,
+  enableDownvotes,
+  enableNsfw,
+  getCommentParentId,
+  getDataTypeString,
+  myAuth,
+  postToCommentSortType,
+  setIsoData,
+  showLocal,
+  updatePersonBlock,
+} from "@utils/app";
+import {
+  getPageFromString,
+  getQueryParams,
+  getQueryString,
+  getRandomFromList,
+} from "@utils/helpers";
+import { canCreateCommunity } from "@utils/roles";
+import type { QueryParams } from "@utils/types";
+import { RouteDataResponse } from "@utils/types";
 import { NoOptionI18nKeys } from "i18next";
-import { Component, linkEvent, MouseEventHandler } from "inferno";
+import { Component, MouseEventHandler, linkEvent } from "inferno";
 import { T } from "inferno-i18next-dess";
 import { Link } from "inferno-router";
 import {
@@ -47,45 +71,22 @@ import {
   SortType,
   TransferCommunity,
 } from "lemmy-js-client";
-import { i18n } from "../../i18next";
+import { fetchLimit, relTags, trendingFetchLimit } from "../../config";
 import {
   CommentViewType,
   DataType,
   InitialFetchRequest,
 } from "../../interfaces";
-import { UserService } from "../../services";
-import { FirstLoadService } from "../../services/FirstLoadService";
-import { HttpService, RequestState } from "../../services/HttpService";
+import { mdToHtml } from "../../markdown";
 import {
-  canCreateCommunity,
-  commentsToFlatNodes,
-  editComment,
-  editPost,
-  editWith,
-  enableDownvotes,
-  enableNsfw,
-  fetchLimit,
-  getCommentParentId,
-  getDataTypeString,
-  getPageFromString,
-  getQueryParams,
-  getQueryString,
-  getRandomFromList,
-  mdToHtml,
-  myAuth,
-  postToCommentSortType,
-  QueryParams,
-  relTags,
-  restoreScrollPosition,
-  RouteDataResponse,
-  saveScrollPosition,
-  setIsoData,
-  setupTippy,
-  showLocal,
-  toast,
-  trendingFetchLimit,
-  updatePersonBlock,
-} from "../../utils";
+  FirstLoadService,
+  HomeCacheService,
+  I18NextService,
+  UserService,
+} from "../../services";
+import { HttpService, RequestState } from "../../services/HttpService";
+import { setupTippy } from "../../tippy";
+import { toast } from "../../toast";
 import { CommentNodes } from "../comment/comment-nodes";
 import { DataTypeSelect } from "../common/data-type-select";
 import { HtmlTags } from "../common/html-tags";
@@ -105,6 +106,7 @@ interface HomeState {
   showTrendingMobile: boolean;
   showSidebarMobile: boolean;
   subscribedCollapsed: boolean;
+  scrolled: boolean;
   tagline?: string;
   siteRes: GetSiteResponse;
   finished: Map<CommentId, boolean | undefined>;
@@ -112,7 +114,7 @@ interface HomeState {
 }
 
 interface HomeProps {
-  listingType: ListingType;
+  listingType?: ListingType;
   dataType: DataType;
   sort: SortType;
   page: number;
@@ -161,12 +163,12 @@ function getDataTypeFromQuery(type?: string): DataType {
   return type ? DataType[type] : DataType.Post;
 }
 
-function getListingTypeFromQuery(type?: string): ListingType {
+function getListingTypeFromQuery(type?: string): ListingType | undefined {
   const myListingType =
     UserService.Instance.myUserInfo?.local_user_view?.local_user
       ?.default_listing_type;
 
-  return (type ? (type as ListingType) : myListingType) ?? "Local";
+  return type ? (type as ListingType) : myListingType;
 }
 
 function getSortTypeFromQuery(type?: string): SortType {
@@ -195,10 +197,10 @@ const MobileButton = ({
   onClick: MouseEventHandler<HTMLButtonElement>;
 }) => (
   <button
-    className="btn btn-secondary d-inline-block mb-2 mr-3"
+    className="btn btn-secondary d-inline-block mb-2 me-3"
     onClick={onClick}
   >
-    {i18n.t(textKey)}{" "}
+    {I18NextService.i18n.t(textKey)}{" "}
     <Icon icon={show ? `minus-square` : `plus-square`} classes="icon-inline" />
   </button>
 );
@@ -210,8 +212,8 @@ const LinkButton = ({
   path: string;
   translationKey: NoOptionI18nKeys;
 }) => (
-  <Link className="btn btn-secondary btn-block" to={path}>
-    {i18n.t(translationKey)}
+  <Link className="btn btn-secondary d-block" to={path}>
+    {I18NextService.i18n.t(translationKey)}
   </Link>
 );
 
@@ -221,6 +223,7 @@ export class Home extends Component<any, HomeState> {
     postsRes: { state: "empty" },
     commentsRes: { state: "empty" },
     trendingCommunitiesRes: { state: "empty" },
+    scrolled: true,
     siteRes: this.isoData.site_res,
     showSubscribedMobile: false,
     showTrendingMobile: false,
@@ -276,11 +279,19 @@ export class Home extends Component<any, HomeState> {
         trendingCommunitiesRes,
         commentsRes,
         postsRes,
-        tagline: getRandomFromList(this.state?.siteRes?.taglines ?? [])
-          ?.content,
         isIsomorphic: true,
       };
+
+      HomeCacheService.postsRes = postsRes;
     }
+
+    this.state.tagline = getRandomFromList(
+      this.state?.siteRes?.taglines ?? []
+    )?.content;
+  }
+
+  componentWillUnmount() {
+    HomeCacheService.activate();
   }
 
   async componentDidMount() {
@@ -296,19 +307,16 @@ export class Home extends Component<any, HomeState> {
     setupTippy();
   }
 
-  componentWillUnmount() {
-    saveScrollPosition(this.context);
-  }
-
   static async fetchInitialData({
     client,
     auth,
     query: { dataType: urlDataType, listingType, page: urlPage, sort: urlSort },
+    site,
   }: InitialFetchRequest<QueryParams<HomeProps>>): Promise<HomeData> {
     const dataType = getDataTypeFromQuery(urlDataType);
-
-    // TODO figure out auth default_listingType, default_sort_type
-    const type_ = getListingTypeFromQuery(listingType);
+    const type_ =
+      getListingTypeFromQuery(listingType) ??
+      site.site_view.local_site.default_post_listing_type;
     const sort = getSortTypeFromQuery(urlSort);
 
     const page = urlPage ? Number(urlPage) : 1;
@@ -375,14 +383,14 @@ export class Home extends Component<any, HomeState> {
     } = this.state;
 
     return (
-      <div className="container-lg">
+      <div className="home container-lg">
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
         />
         {site_setup && (
           <div className="row">
-            <main role="main" className="col-12 col-md-8">
+            <main role="main" className="col-12 col-md-8 col-lg-9">
               {tagline && (
                 <div
                   id="tagline"
@@ -392,7 +400,7 @@ export class Home extends Component<any, HomeState> {
               <div className="d-block d-md-none">{this.mobileView}</div>
               {this.posts}
             </main>
-            <aside className="d-none d-md-block col-md-4">
+            <aside className="d-none d-md-block col-md-4 col-lg-3">
               {this.mySidebar}
             </aside>
           </div>
@@ -566,13 +574,15 @@ export class Home extends Component<any, HomeState> {
               className="btn btn-sm text-muted"
               onClick={linkEvent(this, this.handleCollapseSubscribe)}
               aria-label={
-                subscribedCollapsed ? i18n.t("expand") : i18n.t("collapse")
+                subscribedCollapsed
+                  ? I18NextService.i18n.t("expand")
+                  : I18NextService.i18n.t("collapse")
               }
               data-tippy-content={
-                subscribedCollapsed ? i18n.t("expand") : i18n.t("collapse")
+                subscribedCollapsed
+                  ? I18NextService.i18n.t("expand")
+                  : I18NextService.i18n.t("collapse")
               }
-              data-bs-toggle="collapse"
-              data-bs-target="#sidebarSubscribedBody"
               aria-expanded="true"
               aria-controls="sidebarSubscribedBody"
             >
@@ -583,24 +593,25 @@ export class Home extends Component<any, HomeState> {
             </button>
           )}
         </header>
-        <div
-          id="sidebarSubscribedBody"
-          className="collapse show"
-          aria-labelledby="sidebarSubscribedHeader"
-        >
-          <div className="card-body">
-            <ul className="list-inline mb-0">
-              {UserService.Instance.myUserInfo?.follows.map(cfv => (
-                <li
-                  key={cfv.community.id}
-                  className="list-inline-item d-inline-block"
-                >
-                  <CommunityLink community={cfv.community} />
-                </li>
-              ))}
-            </ul>
+        {!subscribedCollapsed && (
+          <div
+            id="sidebarSubscribedBody"
+            aria-labelledby="sidebarSubscribedHeader"
+          >
+            <div className="card-body">
+              <ul className="list-inline mb-0">
+                {UserService.Instance.myUserInfo?.follows.map(cfv => (
+                  <li
+                    key={cfv.community.id}
+                    className="list-inline-item d-inline-block"
+                  >
+                    <CommunityLink community={cfv.community} />
+                  </li>
+                ))}
+              </ul>
+            </div>
           </div>
-        </div>
+        )}
       </>
     );
   }
@@ -625,6 +636,11 @@ export class Home extends Component<any, HomeState> {
       search: getQueryString(queryParams),
     });
 
+    if (!this.state.scrolled) {
+      this.setState({ scrolled: true });
+      setTimeout(() => window.scrollTo(0, 0), 0);
+    }
+
     await this.fetchData();
   }
 
@@ -647,7 +663,9 @@ export class Home extends Component<any, HomeState> {
     const siteRes = this.state.siteRes;
 
     if (dataType === DataType.Post) {
-      switch (this.state.postsRes.state) {
+      switch (this.state.postsRes?.state) {
+        case "empty":
+          return <div style="min-height: 20000px;"></div>;
         case "loading":
           return (
             <h5>
@@ -735,25 +753,33 @@ export class Home extends Component<any, HomeState> {
     const { listingType, dataType, sort } = getHomeQueryParams();
 
     return (
-      <div className="mb-3">
-        <span className="mr-3">
+      <div className="row align-items-center mb-3 g-3">
+        <div className="col-auto">
           <DataTypeSelect
             type_={dataType}
             onChange={this.handleDataTypeChange}
           />
-        </span>
-        <span className="mr-3">
+        </div>
+        <div className="col-auto">
           <ListingTypeSelect
-            type_={listingType}
+            type_={
+              listingType ??
+              this.state.siteRes.site_view.local_site.default_post_listing_type
+            }
             showLocal={showLocal(this.isoData)}
             showSubscribed
             onChange={this.handleListingTypeChange}
           />
-        </span>
-        <span className="mr-2">
+        </div>
+        <div className="col-auto">
           <SortSelect sort={sort} onChange={this.handleSortChange} />
-        </span>
-        {getRss(listingType)}
+        </div>
+        <div className="col-auto ps-0">
+          {getRss(
+            listingType ??
+              this.state.siteRes.site_view.local_site.default_post_listing_type
+          )}
+        </div>
       </div>
     );
   }
@@ -775,17 +801,30 @@ export class Home extends Component<any, HomeState> {
     const { dataType, page, listingType, sort } = getHomeQueryParams();
 
     if (dataType === DataType.Post) {
-      this.setState({ postsRes: { state: "loading" } });
-      this.setState({
-        postsRes: await HttpService.client.getPosts({
-          page,
-          limit: fetchLimit,
-          sort,
-          saved_only: false,
-          type_: listingType,
-          auth,
-        }),
-      });
+      if (HomeCacheService.active) {
+        const { postsRes, scrollY } = HomeCacheService;
+        HomeCacheService.deactivate();
+        this.setState({ postsRes });
+        window.scrollTo({
+          left: 0,
+          top: scrollY,
+          behavior: "instant",
+        });
+      } else {
+        this.setState({ postsRes: { state: "loading" } });
+        this.setState({
+          postsRes: await HttpService.client.getPosts({
+            page,
+            limit: fetchLimit,
+            sort,
+            saved_only: false,
+            type_: listingType,
+            auth,
+          }),
+        });
+
+        HomeCacheService.postsRes = this.state.postsRes;
+      }
     } else {
       this.setState({ commentsRes: { state: "loading" } });
       this.setState({
@@ -800,7 +839,6 @@ export class Home extends Component<any, HomeState> {
       });
     }
 
-    restoreScrollPosition(this.context);
     setupTippy();
   }
 
@@ -821,23 +859,23 @@ export class Home extends Component<any, HomeState> {
   }
 
   handlePageChange(page: number) {
+    this.setState({ scrolled: false });
     this.updateUrl({ page });
-    window.scrollTo(0, 0);
   }
 
   handleSortChange(val: SortType) {
+    this.setState({ scrolled: false });
     this.updateUrl({ sort: val, page: 1 });
-    window.scrollTo(0, 0);
   }
 
   handleListingTypeChange(val: ListingType) {
+    this.setState({ scrolled: false });
     this.updateUrl({ listingType: val, page: 1 });
-    window.scrollTo(0, 0);
   }
 
   handleDataTypeChange(val: DataType) {
+    this.setState({ scrolled: false });
     this.updateUrl({ dataType: val, page: 1 });
-    window.scrollTo(0, 0);
   }
 
   async handleAddModToCommunity(form: AddModToCommunity) {
@@ -934,14 +972,14 @@ export class Home extends Component<any, HomeState> {
   async handleCommentReport(form: CreateCommentReport) {
     const reportRes = await HttpService.client.createCommentReport(form);
     if (reportRes.state == "success") {
-      toast(i18n.t("report_created"));
+      toast(I18NextService.i18n.t("report_created"));
     }
   }
 
   async handlePostReport(form: CreatePostReport) {
     const reportRes = await HttpService.client.createPostReport(form);
     if (reportRes.state == "success") {
-      toast(i18n.t("report_created"));
+      toast(I18NextService.i18n.t("report_created"));
     }
   }
 
@@ -965,7 +1003,7 @@ export class Home extends Component<any, HomeState> {
 
   async handleTransferCommunity(form: TransferCommunity) {
     await HttpService.client.transferCommunity(form);
-    toast(i18n.t("transfer_community"));
+    toast(I18NextService.i18n.t("transfer_community"));
   }
 
   async handleCommentReplyRead(form: MarkCommentReplyAsRead) {
@@ -1032,7 +1070,7 @@ export class Home extends Component<any, HomeState> {
 
   purgeItem(purgeRes: RequestState<PurgeItemResponse>) {
     if (purgeRes.state == "success") {
-      toast(i18n.t("purge_success"));
+      toast(I18NextService.i18n.t("purge_success"));
       this.context.router.history.push(`/`);
     }
   }