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