]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/instances.tsx
Fix server-side rendering after first load.
[lemmy-ui.git] / src / shared / components / home / instances.tsx
1 import { setIsoData } from "@utils/app";
2 import { isBrowser } from "@utils/browser";
3 import { RouteDataResponse } from "@utils/types";
4 import { Component } from "inferno";
5 import {
6   GetFederatedInstancesResponse,
7   GetSiteResponse,
8   Instance,
9 } from "lemmy-js-client";
10 import { relTags } from "../../config";
11 import { InitialFetchRequest } from "../../interfaces";
12 import { FirstLoadService, I18NextService } from "../../services";
13 import { HttpService, RequestState } from "../../services/HttpService";
14 import { HtmlTags } from "../common/html-tags";
15 import { Spinner } from "../common/icon";
16
17 type InstancesData = RouteDataResponse<{
18   federatedInstancesResponse: GetFederatedInstancesResponse;
19 }>;
20
21 interface InstancesState {
22   instancesRes: RequestState<GetFederatedInstancesResponse>;
23   siteRes: GetSiteResponse;
24   isIsomorphic: boolean;
25 }
26
27 export class Instances extends Component<any, InstancesState> {
28   private isoData = setIsoData<InstancesData>(this.context);
29   state: InstancesState = {
30     instancesRes: { state: "empty" },
31     siteRes: this.isoData.site_res,
32     isIsomorphic: false,
33   };
34
35   constructor(props: any, context: any) {
36     super(props, context);
37
38     // Only fetch the data if coming from another route
39     if (!isBrowser() || FirstLoadService.isFirstLoad) {
40       this.state = {
41         ...this.state,
42         instancesRes: this.isoData.routeData.federatedInstancesResponse,
43         isIsomorphic: true,
44       };
45     }
46   }
47
48   async componentDidMount() {
49     if (!this.state.isIsomorphic) {
50       await this.fetchInstances();
51     }
52   }
53
54   async fetchInstances() {
55     this.setState({
56       instancesRes: { state: "loading" },
57     });
58
59     this.setState({
60       instancesRes: await HttpService.client.getFederatedInstances({}),
61     });
62   }
63
64   static async fetchInitialData({
65     client,
66   }: InitialFetchRequest): Promise<InstancesData> {
67     return {
68       federatedInstancesResponse: await client.getFederatedInstances({}),
69     };
70   }
71
72   get documentTitle(): string {
73     return `${I18NextService.i18n.t("instances")} - ${
74       this.state.siteRes.site_view.site.name
75     }`;
76   }
77
78   renderInstances() {
79     switch (this.state.instancesRes.state) {
80       case "loading":
81         return (
82           <h5>
83             <Spinner large />
84           </h5>
85         );
86       case "success": {
87         const instances = this.state.instancesRes.data.federated_instances;
88         return instances ? (
89           <div className="row">
90             <div className="col-md-6">
91               <h5>{I18NextService.i18n.t("linked_instances")}</h5>
92               {this.itemList(instances.linked)}
93             </div>
94             {instances.allowed && instances.allowed.length > 0 && (
95               <div className="col-md-6">
96                 <h5>{I18NextService.i18n.t("allowed_instances")}</h5>
97                 {this.itemList(instances.allowed)}
98               </div>
99             )}
100             {instances.blocked && instances.blocked.length > 0 && (
101               <div className="col-md-6">
102                 <h5>{I18NextService.i18n.t("blocked_instances")}</h5>
103                 {this.itemList(instances.blocked)}
104               </div>
105             )}
106           </div>
107         ) : (
108           <></>
109         );
110       }
111     }
112   }
113
114   render() {
115     return (
116       <div className="home-instances container-lg">
117         <HtmlTags
118           title={this.documentTitle}
119           path={this.context.router.route.match.url}
120         />
121         {this.renderInstances()}
122       </div>
123     );
124   }
125
126   itemList(items: Instance[]) {
127     return items.length > 0 ? (
128       <div className="table-responsive">
129         <table id="instances_table" className="table table-sm table-hover">
130           <thead className="pointer">
131             <tr>
132               <th>{I18NextService.i18n.t("name")}</th>
133               <th>{I18NextService.i18n.t("software")}</th>
134               <th>{I18NextService.i18n.t("version")}</th>
135             </tr>
136           </thead>
137           <tbody>
138             {items.map(i => (
139               <tr key={i.domain}>
140                 <td>
141                   <a href={`https://${i.domain}`} rel={relTags}>
142                     {i.domain}
143                   </a>
144                 </td>
145                 <td>{i.software}</td>
146                 <td>{i.version}</td>
147               </tr>
148             ))}
149           </tbody>
150         </table>
151       </div>
152     ) : (
153       <div>{I18NextService.i18n.t("none_found")}</div>
154     );
155   }
156 }