]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/create-post.tsx
Fix I18 next circular reference
[lemmy-ui.git] / src / shared / components / post / create-post.tsx
1 import { enableDownvotes, enableNsfw, myAuth, setIsoData } from "@utils/app";
2 import { getIdFromString, getQueryParams } from "@utils/helpers";
3 import type { QueryParams } from "@utils/types";
4 import { Choice, RouteDataResponse } from "@utils/types";
5 import { Component } from "inferno";
6 import { RouteComponentProps } from "inferno-router/dist/Route";
7 import {
8   CreatePost as CreatePostI,
9   GetCommunity,
10   GetCommunityResponse,
11   GetSiteResponse,
12   ListCommunitiesResponse,
13 } from "lemmy-js-client";
14 import { InitialFetchRequest, PostFormParams } from "../../interfaces";
15 import { FirstLoadService, I18NextService } from "../../services";
16 import {
17   HttpService,
18   RequestState,
19   WrappedLemmyHttp,
20 } from "../../services/HttpService";
21 import { HtmlTags } from "../common/html-tags";
22 import { Spinner } from "../common/icon";
23 import { PostForm } from "./post-form";
24
25 export interface CreatePostProps {
26   communityId?: number;
27 }
28
29 type CreatePostData = RouteDataResponse<{
30   communityResponse: GetCommunityResponse;
31   initialCommunitiesRes: ListCommunitiesResponse;
32 }>;
33
34 function getCreatePostQueryParams() {
35   return getQueryParams<CreatePostProps>({
36     communityId: getIdFromString,
37   });
38 }
39
40 function fetchCommunitiesForOptions(client: WrappedLemmyHttp) {
41   return client.listCommunities({ limit: 30, sort: "TopMonth", type_: "All" });
42 }
43
44 interface CreatePostState {
45   siteRes: GetSiteResponse;
46   loading: boolean;
47   selectedCommunityChoice?: Choice;
48   initialCommunitiesRes: RequestState<ListCommunitiesResponse>;
49   isIsomorphic: boolean;
50 }
51
52 export class CreatePost extends Component<
53   RouteComponentProps<Record<string, never>>,
54   CreatePostState
55 > {
56   private isoData = setIsoData<CreatePostData>(this.context);
57   state: CreatePostState = {
58     siteRes: this.isoData.site_res,
59     loading: true,
60     initialCommunitiesRes: { state: "empty" },
61     isIsomorphic: false,
62   };
63
64   constructor(props: RouteComponentProps<Record<string, never>>, context: any) {
65     super(props, context);
66
67     this.handlePostCreate = this.handlePostCreate.bind(this);
68     this.handleSelectedCommunityChange =
69       this.handleSelectedCommunityChange.bind(this);
70
71     // Only fetch the data if coming from another route
72     if (FirstLoadService.isFirstLoad) {
73       const { communityResponse: communityRes, initialCommunitiesRes } =
74         this.isoData.routeData;
75
76       this.state = {
77         ...this.state,
78         loading: false,
79         initialCommunitiesRes,
80         isIsomorphic: true,
81       };
82
83       if (communityRes?.state === "success") {
84         const communityChoice: Choice = {
85           label: communityRes.data.community_view.community.title,
86           value: communityRes.data.community_view.community.id.toString(),
87         };
88
89         this.state = {
90           ...this.state,
91           selectedCommunityChoice: communityChoice,
92         };
93       }
94     }
95   }
96
97   async fetchCommunity() {
98     const { communityId } = getCreatePostQueryParams();
99     const auth = myAuth();
100
101     if (communityId) {
102       const res = await HttpService.client.getCommunity({
103         id: communityId,
104         auth,
105       });
106       if (res.state === "success") {
107         this.setState({
108           selectedCommunityChoice: {
109             label: res.data.community_view.community.title,
110             value: res.data.community_view.community.id.toString(),
111           },
112           loading: false,
113         });
114       }
115     }
116   }
117
118   async componentDidMount() {
119     // TODO test this
120     if (!this.state.isIsomorphic) {
121       const { communityId } = getCreatePostQueryParams();
122
123       const initialCommunitiesRes = await fetchCommunitiesForOptions(
124         HttpService.client
125       );
126
127       this.setState({
128         initialCommunitiesRes,
129       });
130
131       if (
132         communityId?.toString() !== this.state.selectedCommunityChoice?.value
133       ) {
134         await this.fetchCommunity();
135       } else if (!communityId) {
136         this.setState({
137           selectedCommunityChoice: undefined,
138           loading: false,
139         });
140       }
141     }
142   }
143
144   get documentTitle(): string {
145     return `${I18NextService.i18n.t("create_post")} - ${
146       this.state.siteRes.site_view.site.name
147     }`;
148   }
149
150   render() {
151     const { selectedCommunityChoice } = this.state;
152
153     const locationState = this.props.history.location.state as
154       | PostFormParams
155       | undefined;
156
157     return (
158       <div className="create-post container-lg">
159         <HtmlTags
160           title={this.documentTitle}
161           path={this.context.router.route.match.url}
162         />
163         {this.state.loading ? (
164           <h5>
165             <Spinner large />
166           </h5>
167         ) : (
168           <div className="row">
169             <div
170               id="createPostForm"
171               className="col-12 col-lg-6 offset-lg-3 mb-4"
172             >
173               <h1 className="h4">{I18NextService.i18n.t("create_post")}</h1>
174               <PostForm
175                 onCreate={this.handlePostCreate}
176                 params={locationState}
177                 enableDownvotes={enableDownvotes(this.state.siteRes)}
178                 enableNsfw={enableNsfw(this.state.siteRes)}
179                 allLanguages={this.state.siteRes.all_languages}
180                 siteLanguages={this.state.siteRes.discussion_languages}
181                 selectedCommunityChoice={selectedCommunityChoice}
182                 onSelectCommunity={this.handleSelectedCommunityChange}
183                 initialCommunities={
184                   this.state.initialCommunitiesRes.state === "success"
185                     ? this.state.initialCommunitiesRes.data.communities
186                     : []
187                 }
188               />
189             </div>
190           </div>
191         )}
192       </div>
193     );
194   }
195
196   async updateUrl({ communityId }: Partial<CreatePostProps>) {
197     const { communityId: urlCommunityId } = getCreatePostQueryParams();
198
199     const locationState = this.props.history.location.state as
200       | PostFormParams
201       | undefined;
202
203     const url = new URL(location.href);
204
205     const newId = (communityId ?? urlCommunityId)?.toString();
206
207     if (newId !== undefined) {
208       url.searchParams.set("communityId", newId);
209     } else {
210       url.searchParams.delete("communityId");
211     }
212
213     history.replaceState(locationState, "", url);
214
215     await this.fetchCommunity();
216   }
217
218   handleSelectedCommunityChange(choice: Choice) {
219     this.updateUrl({
220       communityId: getIdFromString(choice?.value),
221     });
222   }
223
224   async handlePostCreate(form: CreatePostI) {
225     const res = await HttpService.client.createPost(form);
226
227     if (res.state === "success") {
228       const postId = res.data.post_view.post.id;
229       this.props.history.replace(`/post/${postId}`);
230     } else {
231       this.setState({
232         loading: false,
233       });
234     }
235   }
236
237   static async fetchInitialData({
238     client,
239     query: { communityId },
240     auth,
241   }: InitialFetchRequest<
242     QueryParams<CreatePostProps>
243   >): Promise<CreatePostData> {
244     const data: CreatePostData = {
245       initialCommunitiesRes: await fetchCommunitiesForOptions(client),
246       communityResponse: { state: "empty" },
247     };
248
249     if (communityId) {
250       const form: GetCommunity = {
251         auth,
252         id: getIdFromString(communityId),
253       };
254
255       data.communityResponse = await client.getCommunity(form);
256     }
257
258     return data;
259   }
260 }