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