]> Untitled Git - lemmy-ui.git/commitdiff
Merge branch 'main' into route-data-refactor
authorabias <abias1122@gmail.com>
Fri, 16 Jun 2023 22:17:17 +0000 (18:17 -0400)
committerabias <abias1122@gmail.com>
Fri, 16 Jun 2023 22:17:17 +0000 (18:17 -0400)
20 files changed:
package.json
src/server/index.tsx
src/shared/components/community/communities.tsx
src/shared/components/community/community.tsx
src/shared/components/home/admin-settings.tsx
src/shared/components/home/home.tsx
src/shared/components/home/instances.tsx
src/shared/components/modlog.tsx
src/shared/components/person/inbox.tsx
src/shared/components/person/profile.tsx
src/shared/components/person/registration-applications.tsx
src/shared/components/person/reports.tsx
src/shared/components/post/create-post.tsx
src/shared/components/post/post.tsx
src/shared/components/private_message/create-private-message.tsx
src/shared/components/search.tsx
src/shared/interfaces.ts
src/shared/routes.ts
src/shared/services/HttpService.ts
src/shared/utils.ts

index b7c48c79b070276ac94f7e6c5d536b9abaf393c1..20e5645d7a6429f3f8ff2526f1ef5577c76afca5 100644 (file)
     "start": "yarn build:dev --watch"
   },
   "lint-staged": {
-    "*.{ts,tsx,js}": ["prettier --write", "eslint --fix"],
-    "*.{css, scss}": ["prettier --write"],
-    "package.json": ["sortpack"]
+    "*.{ts,tsx,js}": [
+      "prettier --write",
+      "eslint --fix"
+    ],
+    "*.{css, scss}": [
+      "prettier --write"
+    ],
+    "package.json": [
+      "sortpack"
+    ]
   },
   "dependencies": {
     "@babel/plugin-proposal-decorators": "^7.21.0",
index 3a12ad7e57e56dd6a34e0919aaad120e04effc65..4cff98b54afa3d45b473971c9631d6d89c17188e 100644 (file)
@@ -17,9 +17,10 @@ import {
   ILemmyConfig,
   InitialFetchRequest,
   IsoDataOptionalSite,
+  RouteData,
 } from "../shared/interfaces";
 import { routes } from "../shared/routes";
-import { RequestState, wrapClient } from "../shared/services/HttpService";
+import { FailedRequestState, wrapClient } from "../shared/services/HttpService";
 import {
   ErrorPageData,
   favIconPngUrl,
@@ -136,7 +137,7 @@ server.get("/*", async (req, res) => {
     // This bypasses errors, so that the client can hit the error on its own,
     // in order to remove the jwt on the browser. Necessary for wrong jwts
     let site: GetSiteResponse | undefined = undefined;
-    const routeData: RequestState<any>[] = [];
+    let routeData: RouteData = {};
     let errorPageData: ErrorPageData | undefined = undefined;
     let try_site = await client.getSite(getSiteForm);
     if (try_site.state === "failed" && try_site.msg == "not_logged_in") {
@@ -160,7 +161,7 @@ server.get("/*", async (req, res) => {
         return res.redirect("/setup");
       }
 
-      if (site) {
+      if (site && activeRoute?.fetchInitialData) {
         const initialFetchReq: InitialFetchRequest = {
           client,
           auth,
@@ -169,26 +170,23 @@ server.get("/*", async (req, res) => {
           site,
         };
 
-        if (activeRoute?.fetchInitialData) {
-          routeData.push(
-            ...(await Promise.all([
-              ...activeRoute.fetchInitialData(initialFetchReq),
-            ]))
-          );
-        }
+        routeData = await activeRoute.fetchInitialData(initialFetchReq);
       }
     } else if (try_site.state === "failed") {
       errorPageData = getErrorPageData(new Error(try_site.msg), site);
     }
 
+    const error = Object.values(routeData).find(
+      res => res.state === "failed"
+    ) as FailedRequestState | undefined;
+
     // Redirect to the 404 if there's an API error
-    if (routeData[0] && routeData[0].state === "failed") {
-      const error = routeData[0].msg;
-      console.error(error);
-      if (error === "instance_is_private") {
+    if (error) {
+      console.error(error.msg);
+      if (error.msg === "instance_is_private") {
         return res.redirect(`/signup`);
       } else {
-        errorPageData = getErrorPageData(new Error(error), site);
+        errorPageData = getErrorPageData(new Error(error.msg), site);
       }
     }
 
index 623269439f8642444aad0fcaa6cb8cdb0649d02d..3eb7bd3aa76cde879b0808b95ceeca618ffc4fe2 100644 (file)
@@ -12,6 +12,7 @@ import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
   QueryParams,
+  RouteDataResponse,
   editCommunity,
   getPageFromString,
   getQueryParams,
@@ -30,6 +31,10 @@ import { CommunityLink } from "./community-link";
 
 const communityLimit = 50;
 
+type CommunitiesData = RouteDataResponse<{
+  listCommunitiesResponse: ListCommunitiesResponse;
+}>;
+
 interface CommunitiesState {
   listCommunitiesResponse: RequestState<ListCommunitiesResponse>;
   siteRes: GetSiteResponse;
@@ -47,7 +52,7 @@ function getListingTypeFromQuery(listingType?: string): ListingType {
 }
 
 export class Communities extends Component<any, CommunitiesState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<CommunitiesData>(this.context);
   state: CommunitiesState = {
     listCommunitiesResponse: { state: "empty" },
     siteRes: this.isoData.site_res,
@@ -62,9 +67,11 @@ export class Communities extends Component<any, CommunitiesState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
+      const { listCommunitiesResponse } = this.isoData.routeData;
+
       this.state = {
         ...this.state,
-        listCommunitiesResponse: this.isoData.routeData[0],
+        listCommunitiesResponse,
         isIsomorphic: true,
       };
     }
@@ -274,13 +281,13 @@ export class Communities extends Component<any, CommunitiesState> {
     i.context.router.history.push(`/search?q=${searchParamEncoded}`);
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     query: { listingType, page },
     client,
     auth,
-  }: InitialFetchRequest<QueryParams<CommunitiesProps>>): Promise<
-    RequestState<any>
-  >[] {
+  }: InitialFetchRequest<
+    QueryParams<CommunitiesProps>
+  >): Promise<CommunitiesData> {
     const listCommunitiesForm: ListCommunities = {
       type_: getListingTypeFromQuery(listingType),
       sort: "TopMonth",
@@ -289,7 +296,11 @@ export class Communities extends Component<any, CommunitiesState> {
       auth: auth,
     };
 
-    return [client.listCommunities(listCommunitiesForm)];
+    return {
+      listCommunitiesResponse: await client.listCommunities(
+        listCommunitiesForm
+      ),
+    };
   }
 
   getCommunitiesQueryParams() {
index f2d7ad729a8e492b2944205314ae6e47e88c8dca..6f3c9112f782231e9af853b199414b2174541a10 100644 (file)
@@ -63,6 +63,7 @@ import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
   QueryParams,
+  RouteDataResponse,
   commentsToFlatNodes,
   communityRSSUrl,
   editComment,
@@ -100,6 +101,12 @@ import { SiteSidebar } from "../home/site-sidebar";
 import { PostListings } from "../post/post-listings";
 import { CommunityLink } from "./community-link";
 
+type CommunityData = RouteDataResponse<{
+  communityRes: GetCommunityResponse;
+  postsRes: GetPostsResponse;
+  commentsRes: GetCommentsResponse;
+}>;
+
 interface State {
   communityRes: RequestState<GetCommunityResponse>;
   postsRes: RequestState<GetPostsResponse>;
@@ -140,7 +147,7 @@ export class Community extends Component<
   RouteComponentProps<{ name: string }>,
   State
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<CommunityData>(this.context);
   state: State = {
     communityRes: { state: "empty" },
     postsRes: { state: "empty" },
@@ -194,13 +201,14 @@ export class Community extends Component<
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [communityRes, postsRes, commentsRes] = this.isoData.routeData;
+      const { communityRes, commentsRes, postsRes } = this.isoData.routeData;
+
       this.state = {
         ...this.state,
+        isIsomorphic: true,
+        commentsRes,
         communityRes,
         postsRes,
-        commentsRes,
-        isIsomorphic: true,
       };
     }
   }
@@ -227,23 +235,21 @@ export class Community extends Component<
     saveScrollPosition(this.context);
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     path,
     query: { dataType: urlDataType, page: urlPage, sort: urlSort },
     auth,
   }: InitialFetchRequest<QueryParams<CommunityProps>>): Promise<
-    RequestState<any>
-  >[] {
+    Promise<CommunityData>
+  > {
     const pathSplit = path.split("/");
-    const promises: Promise<RequestState<any>>[] = [];
 
     const communityName = pathSplit[2];
     const communityForm: GetCommunity = {
       name: communityName,
       auth,
     };
-    promises.push(client.getCommunity(communityForm));
 
     const dataType = getDataTypeFromQuery(urlDataType);
 
@@ -251,6 +257,11 @@ export class Community extends Component<
 
     const page = getPageFromString(urlPage);
 
+    let postsResponse: RequestState<GetPostsResponse> = { state: "empty" };
+    let commentsResponse: RequestState<GetCommentsResponse> = {
+      state: "empty",
+    };
+
     if (dataType === DataType.Post) {
       const getPostsForm: GetPosts = {
         community_name: communityName,
@@ -261,8 +272,8 @@ export class Community extends Component<
         saved_only: false,
         auth,
       };
-      promises.push(client.getPosts(getPostsForm));
-      promises.push(Promise.resolve({ state: "empty" }));
+
+      postsResponse = await client.getPosts(getPostsForm);
     } else {
       const getCommentsForm: GetComments = {
         community_name: communityName,
@@ -273,11 +284,15 @@ export class Community extends Component<
         saved_only: false,
         auth,
       };
-      promises.push(Promise.resolve({ state: "empty" }));
-      promises.push(client.getComments(getCommentsForm));
+
+      commentsResponse = await client.getComments(getCommentsForm);
     }
 
-    return promises;
+    return {
+      communityRes: await client.getCommunity(communityForm),
+      commentsRes: commentsResponse,
+      postsRes: postsResponse,
+    };
   }
 
   get documentTitle(): string {
index 302e96bdf85e4a3798ee9af1e5c28e8c2305450d..ad7ac931aead7fbcfb5298535f5eba9f7798d737 100644 (file)
@@ -14,6 +14,7 @@ import { InitialFetchRequest } from "../../interfaces";
 import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
+  RouteDataResponse,
   capitalizeFirstLetter,
   fetchThemeList,
   myAuthRequired,
@@ -32,6 +33,11 @@ import RateLimitForm from "./rate-limit-form";
 import { SiteForm } from "./site-form";
 import { TaglineForm } from "./tagline-form";
 
+type AdminSettingsData = RouteDataResponse<{
+  bannedRes: BannedPersonsResponse;
+  instancesRes: GetFederatedInstancesResponse;
+}>;
+
 interface AdminSettingsState {
   siteRes: GetSiteResponse;
   banned: PersonView[];
@@ -46,7 +52,7 @@ interface AdminSettingsState {
 }
 
 export class AdminSettings extends Component<any, AdminSettingsState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<AdminSettingsData>(this.context);
   state: AdminSettingsState = {
     siteRes: this.isoData.site_res,
     banned: [],
@@ -70,7 +76,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [bannedRes, instancesRes] = this.isoData.routeData;
+      const { bannedRes, instancesRes } = this.isoData.routeData;
+
       this.state = {
         ...this.state,
         bannedRes,
@@ -80,47 +87,18 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     }
   }
 
-  async fetchData() {
-    this.setState({
-      bannedRes: { state: "loading" },
-      instancesRes: { state: "loading" },
-      themeList: [],
-      loading: true,
-    });
-
-    const auth = myAuthRequired();
-
-    const [bannedRes, instancesRes, themeList] = await Promise.all([
-      HttpService.client.getBannedPersons({ auth }),
-      HttpService.client.getFederatedInstances({ auth }),
-      fetchThemeList(),
-    ]);
-
-    this.setState({
-      bannedRes,
-      instancesRes,
-      themeList,
-      loading: false,
-    });
-  }
-
-  static fetchInitialData({
+  static async fetchInitialData({
     auth,
     client,
-  }: InitialFetchRequest): Promise<any>[] {
-    const promises: Promise<RequestState<any>>[] = [];
-
-    if (auth) {
-      promises.push(client.getBannedPersons({ auth }));
-      promises.push(client.getFederatedInstances({ auth }));
-    } else {
-      promises.push(
-        Promise.resolve({ state: "empty" }),
-        Promise.resolve({ state: "empty" })
-      );
-    }
-
-    return promises;
+  }: InitialFetchRequest): Promise<AdminSettingsData> {
+    return {
+      bannedRes: await client.getBannedPersons({
+        auth: auth as string,
+      }),
+      instancesRes: await client.getFederatedInstances({
+        auth: auth as string,
+      }),
+    };
   }
 
   async componentDidMount() {
@@ -218,6 +196,28 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     );
   }
 
+  async fetchData() {
+    this.setState({
+      bannedRes: { state: "loading" },
+      instancesRes: { state: "loading" },
+      themeList: [],
+    });
+
+    const auth = myAuthRequired();
+
+    const [bannedRes, instancesRes, themeList] = await Promise.all([
+      HttpService.client.getBannedPersons({ auth }),
+      HttpService.client.getFederatedInstances({ auth }),
+      fetchThemeList(),
+    ]);
+
+    this.setState({
+      bannedRes,
+      instancesRes,
+      themeList,
+    });
+  }
+
   admins() {
     return (
       <>
index 215075d8fbf3d87da9937bb18b0fa473d56d96ba..67b02e460660dcf0e4db0d72156aca70fb4a4993 100644 (file)
@@ -77,6 +77,7 @@ import {
   QueryParams,
   relTags,
   restoreScrollPosition,
+  RouteDataResponse,
   saveScrollPosition,
   setIsoData,
   setupTippy,
@@ -117,6 +118,45 @@ interface HomeProps {
   page: number;
 }
 
+type HomeData = RouteDataResponse<{
+  postsRes: GetPostsResponse;
+  commentsRes: GetCommentsResponse;
+  trendingCommunitiesRes: ListCommunitiesResponse;
+}>;
+
+function getRss(listingType: ListingType) {
+  const { sort } = getHomeQueryParams();
+  const auth = myAuth();
+
+  let rss: string | undefined = undefined;
+
+  switch (listingType) {
+    case "All": {
+      rss = `/feeds/all.xml?sort=${sort}`;
+      break;
+    }
+    case "Local": {
+      rss = `/feeds/local.xml?sort=${sort}`;
+      break;
+    }
+    case "Subscribed": {
+      rss = auth ? `/feeds/front/${auth}.xml?sort=${sort}` : undefined;
+      break;
+    }
+  }
+
+  return (
+    rss && (
+      <>
+        <a href={rss} rel={relTags} title="RSS">
+          <Icon icon="rss" classes="text-muted small" />
+        </a>
+        <link rel="alternate" type="application/atom+xml" href={rss} />
+      </>
+    )
+  );
+}
+
 function getDataTypeFromQuery(type?: string): DataType {
   return type ? DataType[type] : DataType.Post;
 }
@@ -176,7 +216,7 @@ const LinkButton = ({
 );
 
 export class Home extends Component<any, HomeState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<HomeData>(this.context);
   state: HomeState = {
     postsRes: { state: "empty" },
     commentsRes: { state: "empty" },
@@ -228,14 +268,14 @@ export class Home extends Component<any, HomeState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [postsRes, commentsRes, trendingCommunitiesRes] =
+      const { trendingCommunitiesRes, commentsRes, postsRes } =
         this.isoData.routeData;
 
       this.state = {
         ...this.state,
-        postsRes,
-        commentsRes,
         trendingCommunitiesRes,
+        commentsRes,
+        postsRes,
         tagline: getRandomFromList(this.state?.siteRes?.taglines ?? [])
           ?.content,
         isIsomorphic: true,
@@ -244,7 +284,12 @@ export class Home extends Component<any, HomeState> {
   }
 
   async componentDidMount() {
-    if (!this.state.isIsomorphic || !this.isoData.routeData.length) {
+    if (
+      !this.state.isIsomorphic ||
+      !Object.values(this.isoData.routeData).some(
+        res => res.state === "success" || res.state === "failed"
+      )
+    ) {
       await Promise.all([this.fetchTrendingCommunities(), this.fetchData()]);
     }
 
@@ -255,13 +300,11 @@ export class Home extends Component<any, HomeState> {
     saveScrollPosition(this.context);
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     auth,
     query: { dataType: urlDataType, listingType, page: urlPage, sort: urlSort },
-  }: InitialFetchRequest<QueryParams<HomeProps>>): Promise<
-    RequestState<any>
-  >[] {
+  }: InitialFetchRequest<QueryParams<HomeProps>>): Promise<HomeData> {
     const dataType = getDataTypeFromQuery(urlDataType);
 
     // TODO figure out auth default_listingType, default_sort_type
@@ -270,7 +313,10 @@ export class Home extends Component<any, HomeState> {
 
     const page = urlPage ? Number(urlPage) : 1;
 
-    const promises: Promise<RequestState<any>>[] = [];
+    let postsRes: RequestState<GetPostsResponse> = { state: "empty" };
+    let commentsRes: RequestState<GetCommentsResponse> = {
+      state: "empty",
+    };
 
     if (dataType === DataType.Post) {
       const getPostsForm: GetPosts = {
@@ -282,8 +328,7 @@ export class Home extends Component<any, HomeState> {
         auth,
       };
 
-      promises.push(client.getPosts(getPostsForm));
-      promises.push(Promise.resolve({ state: "empty" }));
+      postsRes = await client.getPosts(getPostsForm);
     } else {
       const getCommentsForm: GetComments = {
         page,
@@ -293,8 +338,8 @@ export class Home extends Component<any, HomeState> {
         saved_only: false,
         auth,
       };
-      promises.push(Promise.resolve({ state: "empty" }));
-      promises.push(client.getComments(getCommentsForm));
+
+      commentsRes = await client.getComments(getCommentsForm);
     }
 
     const trendingCommunitiesForm: ListCommunities = {
@@ -303,9 +348,14 @@ export class Home extends Component<any, HomeState> {
       limit: trendingFetchLimit,
       auth,
     };
-    promises.push(client.listCommunities(trendingCommunitiesForm));
 
-    return promises;
+    return {
+      trendingCommunitiesRes: await client.listCommunities(
+        trendingCommunitiesForm
+      ),
+      commentsRes,
+      postsRes,
+    };
   }
 
   get documentTitle(): string {
@@ -340,7 +390,7 @@ export class Home extends Component<any, HomeState> {
                 ></div>
               )}
               <div className="d-block d-md-none">{this.mobileView}</div>
-              {this.posts()}
+              {this.posts}
             </main>
             <aside className="d-none d-md-block col-md-4">
               {this.mySidebar}
@@ -551,7 +601,7 @@ export class Home extends Component<any, HomeState> {
     await this.fetchData();
   }
 
-  posts() {
+  get posts() {
     const { page } = getHomeQueryParams();
 
     return (
@@ -570,7 +620,7 @@ 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 "loading":
           return (
             <h5>
@@ -676,44 +726,11 @@ export class Home extends Component<any, HomeState> {
         <span className="mr-2">
           <SortSelect sort={sort} onChange={this.handleSortChange} />
         </span>
-        {this.getRss(listingType)}
+        {getRss(listingType)}
       </div>
     );
   }
 
-  getRss(listingType: ListingType) {
-    const { sort } = getHomeQueryParams();
-    const auth = myAuth();
-
-    let rss: string | undefined = undefined;
-
-    switch (listingType) {
-      case "All": {
-        rss = `/feeds/all.xml?sort=${sort}`;
-        break;
-      }
-      case "Local": {
-        rss = `/feeds/local.xml?sort=${sort}`;
-        break;
-      }
-      case "Subscribed": {
-        rss = auth ? `/feeds/front/${auth}.xml?sort=${sort}` : undefined;
-        break;
-      }
-    }
-
-    return (
-      rss && (
-        <>
-          <a href={rss} rel={relTags} title="RSS">
-            <Icon icon="rss" classes="text-muted small" />
-          </a>
-          <link rel="alternate" type="application/atom+xml" href={rss} />
-        </>
-      )
-    );
-  }
-
   async fetchTrendingCommunities() {
     this.setState({ trendingCommunitiesRes: { state: "loading" } });
     this.setState({
index 30cb9dea0c0491a020890c3206d20c14709dd09e..ec2ff63572af0bfa00b4c299ec457d25f95a669e 100644 (file)
@@ -8,10 +8,14 @@ import { i18n } from "../../i18next";
 import { InitialFetchRequest } from "../../interfaces";
 import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
-import { relTags, setIsoData } from "../../utils";
+import { RouteDataResponse, relTags, setIsoData } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
 
+type InstancesData = RouteDataResponse<{
+  federatedInstancesResponse: GetFederatedInstancesResponse;
+}>;
+
 interface InstancesState {
   instancesRes: RequestState<GetFederatedInstancesResponse>;
   siteRes: GetSiteResponse;
@@ -19,7 +23,7 @@ interface InstancesState {
 }
 
 export class Instances extends Component<any, InstancesState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<InstancesData>(this.context);
   state: InstancesState = {
     instancesRes: { state: "empty" },
     siteRes: this.isoData.site_res,
@@ -33,7 +37,7 @@ export class Instances extends Component<any, InstancesState> {
     if (FirstLoadService.isFirstLoad) {
       this.state = {
         ...this.state,
-        instancesRes: this.isoData.routeData[0],
+        instancesRes: this.isoData.routeData.federatedInstancesResponse,
         isIsomorphic: true,
       };
     }
@@ -55,10 +59,12 @@ export class Instances extends Component<any, InstancesState> {
     });
   }
 
-  static fetchInitialData(
-    req: InitialFetchRequest
-  ): Promise<RequestState<any>>[] {
-    return [req.client.getFederatedInstances({})];
+  static async fetchInitialData({
+    client,
+  }: InitialFetchRequest): Promise<InstancesData> {
+    return {
+      federatedInstancesResponse: await client.getFederatedInstances({}),
+    };
   }
 
   get documentTitle(): string {
index d917f5f35ed675842e43169fa6da129b696335b6..b3f1fff1542c44b440c166aa1d6a62b1870945bf 100644 (file)
@@ -13,6 +13,7 @@ import {
   GetModlog,
   GetModlogResponse,
   GetPersonDetails,
+  GetPersonDetailsResponse,
   ModAddCommunityView,
   ModAddView,
   ModBanFromCommunityView,
@@ -34,6 +35,7 @@ import { HttpService, RequestState } from "../services/HttpService";
 import {
   Choice,
   QueryParams,
+  RouteDataResponse,
   amAdmin,
   amMod,
   debounce,
@@ -74,6 +76,13 @@ type View =
   | AdminPurgePostView
   | AdminPurgeCommentView;
 
+type ModlogData = RouteDataResponse<{
+  res: GetModlogResponse;
+  communityRes: GetCommunityResponse;
+  modUserResponse: GetPersonDetailsResponse;
+  userResponse: GetPersonDetailsResponse;
+}>;
+
 interface ModlogType {
   id: number;
   type_: ModlogActionType;
@@ -631,7 +640,7 @@ export class Modlog extends Component<
   RouteComponentProps<{ communityId?: string }>,
   ModlogState
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<ModlogData>(this.context);
 
   state: ModlogState = {
     res: { state: "empty" },
@@ -653,25 +662,26 @@ export class Modlog extends Component<
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [res, communityRes, filteredModRes, filteredUserRes] =
+      const { res, communityRes, modUserResponse, userResponse } =
         this.isoData.routeData;
+
       this.state = {
         ...this.state,
         res,
         communityRes,
       };
 
-      if (filteredModRes.state === "success") {
+      if (modUserResponse.state === "success") {
         this.state = {
           ...this.state,
-          modSearchOptions: [personToChoice(filteredModRes.data.person_view)],
+          modSearchOptions: [personToChoice(modUserResponse.data.person_view)],
         };
       }
 
-      if (filteredUserRes.state === "success") {
+      if (userResponse.state === "success") {
         this.state = {
           ...this.state,
-          userSearchOptions: [personToChoice(filteredUserRes.data.person_view)],
+          userSearchOptions: [personToChoice(userResponse.data.person_view)],
         };
       }
     }
@@ -958,17 +968,14 @@ export class Modlog extends Component<
     }
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     path,
     query: { modId: urlModId, page, userId: urlUserId, actionType },
     auth,
     site,
-  }: InitialFetchRequest<QueryParams<ModlogProps>>): Promise<
-    RequestState<any>
-  >[] {
+  }: InitialFetchRequest<QueryParams<ModlogProps>>): Promise<ModlogData> {
     const pathSplit = path.split("/");
-    const promises: Promise<RequestState<any>>[] = [];
     const communityId = getIdFromString(pathSplit[2]);
     const modId = !site.site_view.local_site.hide_modlog_mod_names
       ? getIdFromString(urlModId)
@@ -985,40 +992,50 @@ export class Modlog extends Component<
       auth,
     };
 
-    promises.push(client.getModlog(modlogForm));
+    let communityResponse: RequestState<GetCommunityResponse> = {
+      state: "empty",
+    };
 
     if (communityId) {
       const communityForm: GetCommunity = {
         id: communityId,
         auth,
       };
-      promises.push(client.getCommunity(communityForm));
-    } else {
-      promises.push(Promise.resolve({ state: "empty" }));
+
+      communityResponse = await client.getCommunity(communityForm);
     }
 
+    let modUserResponse: RequestState<GetPersonDetailsResponse> = {
+      state: "empty",
+    };
+
     if (modId) {
       const getPersonForm: GetPersonDetails = {
         person_id: modId,
         auth,
       };
 
-      promises.push(client.getPersonDetails(getPersonForm));
-    } else {
-      promises.push(Promise.resolve({ state: "empty" }));
+      modUserResponse = await client.getPersonDetails(getPersonForm);
     }
 
+    let userResponse: RequestState<GetPersonDetailsResponse> = {
+      state: "empty",
+    };
+
     if (userId) {
       const getPersonForm: GetPersonDetails = {
         person_id: userId,
         auth,
       };
 
-      promises.push(client.getPersonDetails(getPersonForm));
-    } else {
-      promises.push(Promise.resolve({ state: "empty" }));
+      userResponse = await client.getPersonDetails(getPersonForm);
     }
 
-    return promises;
+    return {
+      res: await client.getModlog(modlogForm),
+      communityRes: communityResponse,
+      modUserResponse,
+      userResponse,
+    };
   }
 }
index 731667c0ddef6108f8fe1a307a4b56fdc66d5338..c65d897b5b675a10720c7019e5eda835387f14fe 100644 (file)
@@ -24,10 +24,7 @@ import {
   DistinguishComment,
   EditComment,
   EditPrivateMessage,
-  GetPersonMentions,
   GetPersonMentionsResponse,
-  GetPrivateMessages,
-  GetReplies,
   GetRepliesResponse,
   GetSiteResponse,
   MarkCommentReplyAsRead,
@@ -53,6 +50,7 @@ import { UserService } from "../../services";
 import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
+  RouteDataResponse,
   commentsToFlatNodes,
   editCommentReply,
   editMention,
@@ -92,6 +90,13 @@ enum ReplyEnum {
   Mention,
   Message,
 }
+
+type InboxData = RouteDataResponse<{
+  repliesRes: GetRepliesResponse;
+  mentionsRes: GetPersonMentionsResponse;
+  messagesRes: PrivateMessagesResponse;
+}>;
+
 type ReplyType = {
   id: number;
   type_: ReplyEnum;
@@ -114,7 +119,7 @@ interface InboxState {
 }
 
 export class Inbox extends Component<any, InboxState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<InboxData>(this.context);
   state: InboxState = {
     unreadOrAll: UnreadOrAll.Unread,
     messageType: MessageType.All,
@@ -162,7 +167,7 @@ export class Inbox extends Component<any, InboxState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [repliesRes, mentionsRes, messagesRes] = this.isoData.routeData;
+      const { mentionsRes, messagesRes, repliesRes } = this.isoData.routeData;
 
       this.state = {
         ...this.state,
@@ -686,50 +691,40 @@ export class Inbox extends Component<any, InboxState> {
     await i.refetch();
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     auth,
-  }: InitialFetchRequest): Promise<any>[] {
-    const promises: Promise<RequestState<any>>[] = [];
-
+  }: InitialFetchRequest): Promise<InboxData> {
     const sort: CommentSortType = "New";
 
-    if (auth) {
-      // It can be /u/me, or /username/1
-      const repliesForm: GetReplies = {
-        sort,
-        unread_only: true,
-        page: 1,
-        limit: fetchLimit,
-        auth,
-      };
-      promises.push(client.getReplies(repliesForm));
-
-      const personMentionsForm: GetPersonMentions = {
-        sort,
-        unread_only: true,
-        page: 1,
-        limit: fetchLimit,
-        auth,
-      };
-      promises.push(client.getPersonMentions(personMentionsForm));
-
-      const privateMessagesForm: GetPrivateMessages = {
-        unread_only: true,
-        page: 1,
-        limit: fetchLimit,
-        auth,
-      };
-      promises.push(client.getPrivateMessages(privateMessagesForm));
-    } else {
-      promises.push(
-        Promise.resolve({ state: "empty" }),
-        Promise.resolve({ state: "empty" }),
-        Promise.resolve({ state: "empty" })
-      );
-    }
-
-    return promises;
+    return {
+      mentionsRes: auth
+        ? await client.getPersonMentions({
+            sort,
+            unread_only: true,
+            page: 1,
+            limit: fetchLimit,
+            auth,
+          })
+        : { state: "empty" },
+      messagesRes: auth
+        ? await client.getPrivateMessages({
+            unread_only: true,
+            page: 1,
+            limit: fetchLimit,
+            auth,
+          })
+        : { state: "empty" },
+      repliesRes: auth
+        ? await client.getReplies({
+            sort,
+            unread_only: true,
+            page: 1,
+            limit: fetchLimit,
+            auth,
+          })
+        : { state: "empty" },
+    };
   }
 
   async refetch() {
index f80d5b907a2f7f1972dc0b62d1bebb51d06df1fe..5466bc5fcb746b2d388a7642725208e007201857 100644 (file)
@@ -54,6 +54,7 @@ import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
   QueryParams,
+  RouteDataResponse,
   canMod,
   capitalizeFirstLetter,
   editComment,
@@ -90,6 +91,10 @@ import { CommunityLink } from "../community/community-link";
 import { PersonDetails } from "./person-details";
 import { PersonListing } from "./person-listing";
 
+type ProfileData = RouteDataResponse<{
+  personResponse: GetPersonDetailsResponse;
+}>;
+
 interface ProfileState {
   personRes: RequestState<GetPersonDetailsResponse>;
   personBlocked: boolean;
@@ -156,7 +161,7 @@ export class Profile extends Component<
   RouteComponentProps<{ username: string }>,
   ProfileState
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<ProfileData>(this.context);
   state: ProfileState = {
     personRes: { state: "empty" },
     personBlocked: false,
@@ -208,7 +213,7 @@ export class Profile extends Component<
     if (FirstLoadService.isFirstLoad) {
       this.state = {
         ...this.state,
-        personRes: this.isoData.routeData[0],
+        personRes: this.isoData.routeData.personResponse,
         isIsomorphic: true,
       };
     }
@@ -267,14 +272,12 @@ export class Profile extends Component<
     }
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     path,
     query: { page, sort, view: urlView },
     auth,
-  }: InitialFetchRequest<QueryParams<ProfileProps>>): Promise<
-    RequestState<any>
-  >[] {
+  }: InitialFetchRequest<QueryParams<ProfileProps>>): Promise<ProfileData> {
     const pathSplit = path.split("/");
 
     const username = pathSplit[2];
@@ -289,7 +292,9 @@ export class Profile extends Component<
       auth,
     };
 
-    return [client.getPersonDetails(form)];
+    return {
+      personResponse: await client.getPersonDetails(form),
+    };
   }
 
   get documentTitle(): string {
index 17b2a02585f8cce401170a24c1c58f70ef6499a0..be1eb2c11da0b976d43e4d7546f6485ce95d22d1 100644 (file)
@@ -2,7 +2,6 @@ import { Component, linkEvent } from "inferno";
 import {
   ApproveRegistrationApplication,
   GetSiteResponse,
-  ListRegistrationApplications,
   ListRegistrationApplicationsResponse,
   RegistrationApplicationView,
 } from "lemmy-js-client";
@@ -12,6 +11,7 @@ import { UserService } from "../../services";
 import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
+  RouteDataResponse,
   editRegistrationApplication,
   fetchLimit,
   myAuthRequired,
@@ -28,6 +28,10 @@ enum UnreadOrAll {
   All,
 }
 
+type RegistrationApplicationsData = RouteDataResponse<{
+  listRegistrationApplicationsResponse: ListRegistrationApplicationsResponse;
+}>;
+
 interface RegistrationApplicationsState {
   appsRes: RequestState<ListRegistrationApplicationsResponse>;
   siteRes: GetSiteResponse;
@@ -40,7 +44,7 @@ export class RegistrationApplications extends Component<
   any,
   RegistrationApplicationsState
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<RegistrationApplicationsData>(this.context);
   state: RegistrationApplicationsState = {
     appsRes: { state: "empty" },
     siteRes: this.isoData.site_res,
@@ -59,7 +63,7 @@ export class RegistrationApplications extends Component<
     if (FirstLoadService.isFirstLoad) {
       this.state = {
         ...this.state,
-        appsRes: this.isoData.routeData[0],
+        appsRes: this.isoData.routeData.listRegistrationApplicationsResponse,
         isIsomorphic: true,
       };
     }
@@ -184,25 +188,20 @@ export class RegistrationApplications extends Component<
     this.refetch();
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     auth,
     client,
-  }: InitialFetchRequest): Promise<any>[] {
-    const promises: Promise<RequestState<any>>[] = [];
-
-    if (auth) {
-      const form: ListRegistrationApplications = {
-        unread_only: true,
-        page: 1,
-        limit: fetchLimit,
-        auth,
-      };
-      promises.push(client.listRegistrationApplications(form));
-    } else {
-      promises.push(Promise.resolve({ state: "empty" }));
-    }
-
-    return promises;
+  }: InitialFetchRequest): Promise<RegistrationApplicationsData> {
+    return {
+      listRegistrationApplicationsResponse: auth
+        ? await client.listRegistrationApplications({
+            unread_only: true,
+            page: 1,
+            limit: fetchLimit,
+            auth: auth as string,
+          })
+        : { state: "empty" },
+    };
   }
 
   async refetch() {
index 29daa3ff6c92dbad9d621d8c2ed9be2e6945985c..99a0333645fe4e719b031eefbba68c5e53862780 100644 (file)
@@ -23,6 +23,7 @@ import { HttpService, UserService } from "../../services";
 import { FirstLoadService } from "../../services/FirstLoadService";
 import { RequestState } from "../../services/HttpService";
 import {
+  RouteDataResponse,
   amAdmin,
   editCommentReport,
   editPostReport,
@@ -56,6 +57,12 @@ enum MessageEnum {
   PrivateMessageReport,
 }
 
+type ReportsData = RouteDataResponse<{
+  commentReportsRes: ListCommentReportsResponse;
+  postReportsRes: ListPostReportsResponse;
+  messageReportsRes: ListPrivateMessageReportsResponse;
+}>;
+
 type ItemType = {
   id: number;
   type_: MessageEnum;
@@ -75,7 +82,7 @@ interface ReportsState {
 }
 
 export class Reports extends Component<any, ReportsState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<ReportsData>(this.context);
   state: ReportsState = {
     commentReportsRes: { state: "empty" },
     postReportsRes: { state: "empty" },
@@ -99,8 +106,9 @@ export class Reports extends Component<any, ReportsState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [commentReportsRes, postReportsRes, messageReportsRes] =
+      const { commentReportsRes, postReportsRes, messageReportsRes } =
         this.isoData.routeData;
+
       this.state = {
         ...this.state,
         commentReportsRes,
@@ -111,7 +119,7 @@ export class Reports extends Component<any, ReportsState> {
       if (amAdmin()) {
         this.state = {
           ...this.state,
-          messageReportsRes,
+          messageReportsRes: messageReportsRes,
         };
       }
     }
@@ -481,55 +489,48 @@ export class Reports extends Component<any, ReportsState> {
     await i.refetch();
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     auth,
     client,
-  }: InitialFetchRequest): Promise<any>[] {
-    const promises: Promise<RequestState<any>>[] = [];
-
+  }: InitialFetchRequest): Promise<ReportsData> {
     const unresolved_only = true;
     const page = 1;
     const limit = fetchLimit;
 
-    if (auth) {
-      const commentReportsForm: ListCommentReports = {
-        unresolved_only,
-        page,
-        limit,
-        auth,
-      };
-      promises.push(client.listCommentReports(commentReportsForm));
+    const commentReportsForm: ListCommentReports = {
+      unresolved_only,
+      page,
+      limit,
+      auth: auth as string,
+    };
 
-      const postReportsForm: ListPostReports = {
+    const postReportsForm: ListPostReports = {
+      unresolved_only,
+      page,
+      limit,
+      auth: auth as string,
+    };
+
+    const data: ReportsData = {
+      commentReportsRes: await client.listCommentReports(commentReportsForm),
+      postReportsRes: await client.listPostReports(postReportsForm),
+      messageReportsRes: { state: "empty" },
+    };
+
+    if (amAdmin()) {
+      const privateMessageReportsForm: ListPrivateMessageReports = {
         unresolved_only,
         page,
         limit,
-        auth,
+        auth: auth as string,
       };
-      promises.push(client.listPostReports(postReportsForm));
 
-      if (amAdmin()) {
-        const privateMessageReportsForm: ListPrivateMessageReports = {
-          unresolved_only,
-          page,
-          limit,
-          auth,
-        };
-        promises.push(
-          client.listPrivateMessageReports(privateMessageReportsForm)
-        );
-      } else {
-        promises.push(Promise.resolve({ state: "empty" }));
-      }
-    } else {
-      promises.push(
-        Promise.resolve({ state: "empty" }),
-        Promise.resolve({ state: "empty" }),
-        Promise.resolve({ state: "empty" })
+      data.messageReportsRes = await client.listPrivateMessageReports(
+        privateMessageReportsForm
       );
     }
 
-    return promises;
+    return data;
   }
 
   async refetch() {
index c7597917740486cd58eae285e54232887737b893..046bc2de5e2c4dd0eeaccf15ae2388ffbde6c55c 100644 (file)
@@ -3,6 +3,7 @@ import { RouteComponentProps } from "inferno-router/dist/Route";
 import {
   CreatePost as CreatePostI,
   GetCommunity,
+  GetCommunityResponse,
   GetSiteResponse,
   ListCommunitiesResponse,
 } from "lemmy-js-client";
@@ -17,6 +18,7 @@ import {
 import {
   Choice,
   QueryParams,
+  RouteDataResponse,
   enableDownvotes,
   enableNsfw,
   getIdFromString,
@@ -32,6 +34,11 @@ export interface CreatePostProps {
   communityId?: number;
 }
 
+type CreatePostData = RouteDataResponse<{
+  communityResponse: GetCommunityResponse;
+  initialCommunitiesRes: ListCommunitiesResponse;
+}>;
+
 function getCreatePostQueryParams() {
   return getQueryParams<CreatePostProps>({
     communityId: getIdFromString,
@@ -54,7 +61,7 @@ export class CreatePost extends Component<
   RouteComponentProps<Record<string, never>>,
   CreatePostState
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<CreatePostData>(this.context);
   state: CreatePostState = {
     siteRes: this.isoData.site_res,
     loading: true,
@@ -71,7 +78,15 @@ export class CreatePost extends Component<
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [communityRes, listCommunitiesRes] = this.isoData.routeData;
+      const { communityResponse: communityRes, initialCommunitiesRes } =
+        this.isoData.routeData;
+
+      this.state = {
+        ...this.state,
+        loading: false,
+        initialCommunitiesRes,
+        isIsomorphic: true,
+      };
 
       if (communityRes?.state === "success") {
         const communityChoice: Choice = {
@@ -84,13 +99,6 @@ export class CreatePost extends Component<
           selectedCommunityChoice: communityChoice,
         };
       }
-
-      this.state = {
-        ...this.state,
-        loading: false,
-        initialCommunitiesRes: listCommunitiesRes,
-        isIsomorphic: true,
-      };
     }
   }
 
@@ -231,14 +239,17 @@ export class CreatePost extends Component<
     }
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     query: { communityId },
     auth,
-  }: InitialFetchRequest<QueryParams<CreatePostProps>>): Promise<
-    RequestState<any>
-  >[] {
-    const promises: Promise<RequestState<any>>[] = [];
+  }: InitialFetchRequest<
+    QueryParams<CreatePostProps>
+  >): Promise<CreatePostData> {
+    const data: CreatePostData = {
+      initialCommunitiesRes: await fetchCommunitiesForOptions(client),
+      communityResponse: { state: "empty" },
+    };
 
     if (communityId) {
       const form: GetCommunity = {
@@ -246,13 +257,9 @@ export class CreatePost extends Component<
         id: getIdFromString(communityId),
       };
 
-      promises.push(client.getCommunity(form));
-    } else {
-      promises.push(Promise.resolve({ state: "empty" }));
+      data.communityResponse = await client.getCommunity(form);
     }
 
-    promises.push(fetchCommunitiesForOptions(client));
-
-    return promises;
+    return data;
   }
 }
index b602f309285cab92ffcdaa40ed7029c371fd916f..7eff1b4a4496d2e7115be1851df6e8de4aac59db 100644 (file)
@@ -77,6 +77,7 @@ import {
   isImage,
   myAuth,
   restoreScrollPosition,
+  RouteDataResponse,
   saveScrollPosition,
   setIsoData,
   setupTippy,
@@ -93,6 +94,11 @@ import { PostListing } from "./post-listing";
 
 const commentsShownInterval = 15;
 
+type PostData = RouteDataResponse<{
+  postRes: GetPostResponse;
+  commentsRes: GetCommentsResponse;
+}>;
+
 interface PostState {
   postId?: number;
   commentId?: number;
@@ -110,7 +116,7 @@ interface PostState {
 }
 
 export class Post extends Component<any, PostState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<PostData>(this.context);
   private commentScrollDebounced: () => void;
   state: PostState = {
     postRes: { state: "empty" },
@@ -169,7 +175,7 @@ export class Post extends Component<any, PostState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [postRes, commentsRes] = this.isoData.routeData;
+      const { commentsRes, postRes } = this.isoData.routeData;
 
       this.state = {
         ...this.state,
@@ -220,13 +226,12 @@ export class Post extends Component<any, PostState> {
     }
   }
 
-  static fetchInitialData({
-    auth,
+  static async fetchInitialData({
     client,
     path,
-  }: InitialFetchRequest): Promise<any>[] {
+    auth,
+  }: InitialFetchRequest): Promise<PostData> {
     const pathSplit = path.split("/");
-    const promises: Promise<RequestState<any>>[] = [];
 
     const pathType = pathSplit.at(1);
     const id = pathSplit.at(2) ? Number(pathSplit.at(2)) : undefined;
@@ -252,10 +257,10 @@ export class Post extends Component<any, PostState> {
       commentsForm.parent_id = id;
     }
 
-    promises.push(client.getPost(postForm));
-    promises.push(client.getComments(commentsForm));
-
-    return promises;
+    return {
+      postRes: await client.getPost(postForm),
+      commentsRes: await client.getComments(commentsForm),
+    };
   }
 
   componentWillUnmount() {
index 817cfd880d001181958b56edce97c340af245040..5b9eb9819840a20d54850d4d08d123b774484988 100644 (file)
@@ -10,6 +10,7 @@ import { InitialFetchRequest } from "../../interfaces";
 import { FirstLoadService } from "../../services/FirstLoadService";
 import { HttpService, RequestState } from "../../services/HttpService";
 import {
+  RouteDataResponse,
   getRecipientIdFromProps,
   myAuth,
   setIsoData,
@@ -19,6 +20,10 @@ import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
 import { PrivateMessageForm } from "./private-message-form";
 
+type CreatePrivateMessageData = RouteDataResponse<{
+  recipientDetailsResponse: GetPersonDetailsResponse;
+}>;
+
 interface CreatePrivateMessageState {
   siteRes: GetSiteResponse;
   recipientRes: RequestState<GetPersonDetailsResponse>;
@@ -30,7 +35,7 @@ export class CreatePrivateMessage extends Component<
   any,
   CreatePrivateMessageState
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<CreatePrivateMessageData>(this.context);
   state: CreatePrivateMessageState = {
     siteRes: this.isoData.site_res,
     recipientRes: { state: "empty" },
@@ -47,7 +52,7 @@ export class CreatePrivateMessage extends Component<
     if (FirstLoadService.isFirstLoad) {
       this.state = {
         ...this.state,
-        recipientRes: this.isoData.routeData[0],
+        recipientRes: this.isoData.routeData.recipientDetailsResponse,
         isIsomorphic: true,
       };
     }
@@ -59,6 +64,25 @@ export class CreatePrivateMessage extends Component<
     }
   }
 
+  static async fetchInitialData({
+    client,
+    path,
+    auth,
+  }: InitialFetchRequest): Promise<CreatePrivateMessageData> {
+    const person_id = Number(path.split("/").pop());
+
+    const form: GetPersonDetails = {
+      person_id,
+      sort: "New",
+      saved_only: false,
+      auth,
+    };
+
+    return {
+      recipientDetailsResponse: await client.getPersonDetails(form),
+    };
+  }
+
   async fetchPersonDetails() {
     this.setState({
       recipientRes: { state: "loading" },
@@ -74,19 +98,6 @@ export class CreatePrivateMessage extends Component<
     });
   }
 
-  static fetchInitialData(
-    req: InitialFetchRequest
-  ): Promise<RequestState<any>>[] {
-    const person_id = Number(req.path.split("/").pop());
-    const form: GetPersonDetails = {
-      person_id,
-      sort: "New",
-      saved_only: false,
-      auth: req.auth,
-    };
-    return [req.client.getPersonDetails(form)];
-  }
-
   get documentTitle(): string {
     if (this.state.recipientRes.state == "success") {
       const name_ = this.state.recipientRes.data.person_view.person.name;
index 8097dbde433b7ac7ef3811e47cc44cd6d4ffe76b..054cab016be94dd34e2b3294a1bd4825590cc75d 100644 (file)
@@ -27,6 +27,7 @@ import { HttpService, RequestState } from "../services/HttpService";
 import {
   Choice,
   QueryParams,
+  RouteDataResponse,
   capitalizeFirstLetter,
   commentsToFlatNodes,
   communityToChoice,
@@ -70,6 +71,14 @@ interface SearchProps {
   page: number;
 }
 
+type SearchData = RouteDataResponse<{
+  communityResponse: GetCommunityResponse;
+  listCommunitiesResponse: ListCommunitiesResponse;
+  creatorDetailsResponse: GetPersonDetailsResponse;
+  searchResponse: SearchResponse;
+  resolveObjectResponse: ResolveObjectResponse;
+}>;
+
 type FilterType = "creator" | "community";
 
 interface SearchState {
@@ -228,7 +237,8 @@ function getListing(
 }
 
 export class Search extends Component<any, SearchState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<SearchData>(this.context);
+
   state: SearchState = {
     resolveObjectRes: { state: "empty" },
     creatorDetailsRes: { state: "empty" },
@@ -262,42 +272,63 @@ export class Search extends Component<any, SearchState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [
-        communityRes,
-        communitiesRes,
-        creatorDetailsRes,
-        searchRes,
-        resolveObjectRes,
-      ] = this.isoData.routeData;
+      const {
+        communityResponse: communityRes,
+        creatorDetailsResponse: creatorDetailsRes,
+        listCommunitiesResponse: communitiesRes,
+        resolveObjectResponse: resolveObjectRes,
+        searchResponse: searchRes,
+      } = this.isoData.routeData;
 
       this.state = {
         ...this.state,
-        communitiesRes,
-        communityRes,
-        creatorDetailsRes,
-        creatorSearchOptions:
-          creatorDetailsRes.state == "success"
-            ? [personToChoice(creatorDetailsRes.data.person_view)]
-            : [],
         isIsomorphic: true,
       };
 
-      if (communityRes.state === "success") {
+      if (creatorDetailsRes?.state === "success") {
+        this.state = {
+          ...this.state,
+          creatorSearchOptions:
+            creatorDetailsRes?.state === "success"
+              ? [personToChoice(creatorDetailsRes.data.person_view)]
+              : [],
+          creatorDetailsRes,
+        };
+      }
+
+      if (communitiesRes?.state === "success") {
         this.state = {
           ...this.state,
-          communitySearchOptions: [
-            communityToChoice(communityRes.data.community_view),
-          ],
+          communitiesRes,
         };
       }
 
-      if (q) {
+      if (communityRes?.state === "success") {
         this.state = {
           ...this.state,
-          searchRes,
-          resolveObjectRes,
+          communityRes,
         };
       }
+
+      if (q !== "") {
+        this.state = {
+          ...this.state,
+        };
+
+        if (searchRes?.state === "success") {
+          this.state = {
+            ...this.state,
+            searchRes,
+          };
+        }
+
+        if (resolveObjectRes?.state === "success") {
+          this.state = {
+            ...this.state,
+            resolveObjectRes,
+          };
+        }
+      }
     }
   }
 
@@ -328,23 +359,25 @@ export class Search extends Component<any, SearchState> {
     saveScrollPosition(this.context);
   }
 
-  static fetchInitialData({
+  static async fetchInitialData({
     client,
     auth,
     query: { communityId, creatorId, q, type, sort, listingType, page },
-  }: InitialFetchRequest<QueryParams<SearchProps>>): Promise<
-    RequestState<any>
-  >[] {
-    const promises: Promise<RequestState<any>>[] = [];
-
+  }: InitialFetchRequest<QueryParams<SearchProps>>): Promise<SearchData> {
     const community_id = getIdFromString(communityId);
+    let communityResponse: RequestState<GetCommunityResponse> = {
+      state: "empty",
+    };
+    let listCommunitiesResponse: RequestState<ListCommunitiesResponse> = {
+      state: "empty",
+    };
     if (community_id) {
       const getCommunityForm: GetCommunity = {
         id: community_id,
         auth,
       };
-      promises.push(client.getCommunity(getCommunityForm));
-      promises.push(Promise.resolve({ state: "empty" }));
+
+      communityResponse = await client.getCommunity(getCommunityForm);
     } else {
       const listCommunitiesForm: ListCommunities = {
         type_: defaultListingType,
@@ -352,23 +385,32 @@ export class Search extends Component<any, SearchState> {
         limit: fetchLimit,
         auth,
       };
-      promises.push(Promise.resolve({ state: "empty" }));
-      promises.push(client.listCommunities(listCommunitiesForm));
+
+      listCommunitiesResponse = await client.listCommunities(
+        listCommunitiesForm
+      );
     }
 
     const creator_id = getIdFromString(creatorId);
+    let creatorDetailsResponse: RequestState<GetPersonDetailsResponse> = {
+      state: "empty",
+    };
     if (creator_id) {
       const getCreatorForm: GetPersonDetails = {
         person_id: creator_id,
         auth,
       };
-      promises.push(client.getPersonDetails(getCreatorForm));
-    } else {
-      promises.push(Promise.resolve({ state: "empty" }));
+
+      creatorDetailsResponse = await client.getPersonDetails(getCreatorForm);
     }
 
     const query = getSearchQueryFromQuery(q);
 
+    let searchResponse: RequestState<SearchResponse> = { state: "empty" };
+    let resolveObjectResponse: RequestState<ResolveObjectResponse> = {
+      state: "empty",
+    };
+
     if (query) {
       const form: SearchForm = {
         q: query,
@@ -383,21 +425,24 @@ export class Search extends Component<any, SearchState> {
       };
 
       if (query !== "") {
-        promises.push(client.search(form));
+        searchResponse = await client.search(form);
         if (auth) {
           const resolveObjectForm: ResolveObject = {
             q: query,
             auth,
           };
-          promises.push(client.resolveObject(resolveObjectForm));
+          resolveObjectResponse = await client.resolveObject(resolveObjectForm);
         }
-      } else {
-        promises.push(Promise.resolve({ state: "empty" }));
-        promises.push(Promise.resolve({ state: "empty" }));
       }
     }
 
-    return promises;
+    return {
+      communityResponse,
+      creatorDetailsResponse,
+      listCommunitiesResponse,
+      resolveObjectResponse,
+      searchResponse,
+    };
   }
 
   get documentTitle(): string {
@@ -463,7 +508,7 @@ export class Search extends Component<any, SearchState> {
           minLength={1}
         />
         <button type="submit" className="btn btn-secondary mr-2 mb-2">
-          {this.state.searchRes.state == "loading" ? (
+          {this.state.searchRes.state === "loading" ? (
             <Spinner />
           ) : (
             <span>{i18n.t("search")}</span>
index 3b64f60533dc246b6fd6fe74f5dfb2387ef29fed..6afebb62c2a68b6c5ae19acf7dac07c20e7ac671 100644 (file)
@@ -6,15 +6,17 @@ import { ErrorPageData } from "./utils";
 /**
  * This contains serialized data, it needs to be deserialized before use.
  */
-export interface IsoData {
+export interface IsoData<T extends RouteData = any> {
   path: string;
-  routeData: RequestState<any>[];
+  routeData: T;
   site_res: GetSiteResponse;
   errorPageData?: ErrorPageData;
 }
 
-export type IsoDataOptionalSite = Partial<IsoData> &
-  Pick<IsoData, Exclude<keyof IsoData, "site_res">>;
+export type IsoDataOptionalSite<T extends RouteData = any> = Partial<
+  IsoData<T>
+> &
+  Pick<IsoData<T>, Exclude<keyof IsoData<T>, "site_res">>;
 
 export interface ILemmyConfig {
   wsHost?: string;
@@ -80,3 +82,5 @@ export interface CommentNodeI {
   children: Array<CommentNodeI>;
   depth: number;
 }
+
+export type RouteData = Record<string, RequestState<any>>;
index 4973bec794dbfb26a34b7d20e2cd848dcab52fd7..6e3ed4987edc7062e6c26d76134427b6d1ad619c 100644 (file)
@@ -21,15 +21,13 @@ import { CreatePost } from "./components/post/create-post";
 import { Post } from "./components/post/post";
 import { CreatePrivateMessage } from "./components/private_message/create-private-message";
 import { Search } from "./components/search";
-import { InitialFetchRequest } from "./interfaces";
-import { RequestState } from "./services/HttpService";
+import { InitialFetchRequest, RouteData } from "./interfaces";
 
-interface IRoutePropsWithFetch extends IRouteProps {
-  // TODO Make sure this one is good.
-  fetchInitialData?(req: InitialFetchRequest): Promise<RequestState<any>>[];
+interface IRoutePropsWithFetch<T extends RouteData> extends IRouteProps {
+  fetchInitialData?(req: InitialFetchRequest): Promise<T>;
 }
 
-export const routes: IRoutePropsWithFetch[] = [
+export const routes: IRoutePropsWithFetch<Record<string, any>>[] = [
   {
     path: `/`,
     component: Home,
index b0e476e2e55dca8c3432b7e396427c8b7f1d2ef4..cdcf11d7632a0089c9757c51c5d80abfa0a22f2a 100644 (file)
@@ -11,7 +11,7 @@ type LoadingRequestState = {
   state: "loading";
 };
 
-type FailedRequestState = {
+export type FailedRequestState = {
   state: "failed";
   msg: string;
 };
@@ -58,7 +58,7 @@ class WrappedLemmyHttpClient {
 
             return {
               data: res,
-              state: "success",
+              state: !(res === undefined || res === null) ? "success" : "empty",
             };
           } catch (error) {
             console.error(`API error: ${error}`);
index df7673a47b6a1e8e860a41b764bf70c58745b464..7007a214ffdeb67a48338ae3b6ed2b5dae29ee38 100644 (file)
@@ -43,8 +43,15 @@ import tippy from "tippy.js";
 import Toastify from "toastify-js";
 import { getHttpBase } from "./env";
 import { i18n } from "./i18next";
-import { CommentNodeI, DataType, IsoData, VoteType } from "./interfaces";
+import {
+  CommentNodeI,
+  DataType,
+  IsoData,
+  RouteData,
+  VoteType,
+} from "./interfaces";
 import { HttpService, UserService } from "./services";
+import { RequestState } from "./services/HttpService";
 
 let Tribute: any;
 if (isBrowser()) {
@@ -1145,7 +1152,7 @@ export function isBrowser() {
   return typeof window !== "undefined";
 }
 
-export function setIsoData(context: any): IsoData {
+export function setIsoData<T extends RouteData>(context: any): IsoData<T> {
   // If its the browser, you need to deserialize the data from the window
   if (isBrowser()) {
     return window.isoData;
@@ -1475,6 +1482,10 @@ export function newVote(voteType: VoteType, myVote?: number): number {
   }
 }
 
+export type RouteDataResponse<T extends Record<string, any>> = {
+  [K in keyof T]: RequestState<T[K]>;
+};
+
 function sleep(millis: number): Promise<void> {
   return new Promise(resolve => setTimeout(resolve, millis));
 }