]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/create-post.tsx
Merge branch 'main' into rate-limiting-tab
[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   GetCommunity,
5   GetCommunityResponse,
6   GetSiteResponse,
7   PostView,
8   UserOperation,
9   wsJsonToRes,
10   wsUserOp,
11 } from "lemmy-js-client";
12 import { Subscription } from "rxjs";
13 import { InitialFetchRequest, PostFormParams } from "shared/interfaces";
14 import { i18n } from "../../i18next";
15 import { WebSocketService } from "../../services";
16 import {
17   Choice,
18   QueryParams,
19   enableDownvotes,
20   enableNsfw,
21   getIdFromString,
22   getQueryParams,
23   getQueryString,
24   isBrowser,
25   myAuth,
26   setIsoData,
27   toast,
28   wsClient,
29   wsSubscribe,
30 } from "../../utils";
31 import { HtmlTags } from "../common/html-tags";
32 import { Spinner } from "../common/icon";
33 import { PostForm } from "./post-form";
34
35 export interface CreatePostProps {
36   communityId?: number;
37 }
38
39 function getCreatePostQueryParams() {
40   return getQueryParams<CreatePostProps>({
41     communityId: getIdFromString,
42   });
43 }
44
45 interface CreatePostState {
46   siteRes: GetSiteResponse;
47   loading: boolean;
48   selectedCommunityChoice?: Choice;
49 }
50
51 export class CreatePost extends Component<
52   RouteComponentProps<Record<string, never>>,
53   CreatePostState
54 > {
55   private isoData = setIsoData(this.context);
56   private subscription?: Subscription;
57   state: CreatePostState = {
58     siteRes: this.isoData.site_res,
59     loading: true,
60   };
61
62   constructor(props: RouteComponentProps<Record<string, never>>, context: any) {
63     super(props, context);
64
65     this.handlePostCreate = this.handlePostCreate.bind(this);
66     this.handleSelectedCommunityChange =
67       this.handleSelectedCommunityChange.bind(this);
68
69     this.parseMessage = this.parseMessage.bind(this);
70     this.subscription = wsSubscribe(this.parseMessage);
71
72     // Only fetch the data if coming from another route
73     if (this.isoData.path === this.context.router.route.match.url) {
74       const communityRes = this.isoData.routeData[0] as
75         | GetCommunityResponse
76         | undefined;
77
78       if (communityRes) {
79         const communityChoice: Choice = {
80           label: communityRes.community_view.community.name,
81           value: communityRes.community_view.community.id.toString(),
82         };
83
84         this.state = {
85           ...this.state,
86           selectedCommunityChoice: communityChoice,
87         };
88       }
89
90       this.state = {
91         ...this.state,
92         loading: false,
93       };
94     } else {
95       this.fetchCommunity();
96     }
97   }
98
99   fetchCommunity() {
100     const { communityId } = getCreatePostQueryParams();
101     const auth = myAuth(false);
102
103     if (communityId) {
104       const form: GetCommunity = {
105         id: communityId,
106         auth,
107       };
108
109       WebSocketService.Instance.send(wsClient.getCommunity(form));
110     }
111   }
112
113   componentDidMount(): void {
114     const { communityId } = getCreatePostQueryParams();
115
116     if (communityId?.toString() !== this.state.selectedCommunityChoice?.value) {
117       this.fetchCommunity();
118     } else if (!communityId) {
119       this.setState({
120         selectedCommunityChoice: undefined,
121         loading: false,
122       });
123     }
124   }
125
126   componentWillUnmount() {
127     if (isBrowser()) {
128       this.subscription?.unsubscribe();
129     }
130   }
131
132   get documentTitle(): string {
133     return `${i18n.t("create_post")} - ${
134       this.state.siteRes.site_view.site.name
135     }`;
136   }
137
138   render() {
139     const { selectedCommunityChoice } = this.state;
140
141     const locationState = this.props.history.location.state as
142       | PostFormParams
143       | undefined;
144
145     return (
146       <div className="container-lg">
147         <HtmlTags
148           title={this.documentTitle}
149           path={this.context.router.route.match.url}
150         />
151         {this.state.loading ? (
152           <h5>
153             <Spinner large />
154           </h5>
155         ) : (
156           <div className="row">
157             <div className="col-12 col-lg-6 offset-lg-3 mb-4">
158               <h5>{i18n.t("create_post")}</h5>
159               <PostForm
160                 onCreate={this.handlePostCreate}
161                 params={locationState}
162                 enableDownvotes={enableDownvotes(this.state.siteRes)}
163                 enableNsfw={enableNsfw(this.state.siteRes)}
164                 allLanguages={this.state.siteRes.all_languages}
165                 siteLanguages={this.state.siteRes.discussion_languages}
166                 selectedCommunityChoice={selectedCommunityChoice}
167                 onSelectCommunity={this.handleSelectedCommunityChange}
168               />
169             </div>
170           </div>
171         )}
172       </div>
173     );
174   }
175
176   updateUrl({ communityId }: Partial<CreatePostProps>) {
177     const { communityId: urlCommunityId } = getCreatePostQueryParams();
178
179     const queryParams: QueryParams<CreatePostProps> = {
180       communityId: (communityId ?? urlCommunityId)?.toString(),
181     };
182
183     const locationState = this.props.history.location.state as
184       | PostFormParams
185       | undefined;
186
187     this.props.history.replace(
188       `/create_post${getQueryString(queryParams)}`,
189       locationState
190     );
191
192     this.fetchCommunity();
193   }
194
195   handleSelectedCommunityChange(choice: Choice) {
196     this.updateUrl({
197       communityId: getIdFromString(choice?.value),
198     });
199   }
200
201   handlePostCreate(post_view: PostView) {
202     this.props.history.replace(`/post/${post_view.post.id}`);
203   }
204
205   static fetchInitialData({
206     client,
207     query: { communityId },
208     auth,
209   }: InitialFetchRequest<QueryParams<CreatePostProps>>): Promise<any>[] {
210     const promises: Promise<any>[] = [];
211
212     if (communityId) {
213       const form: GetCommunity = {
214         auth,
215         id: getIdFromString(communityId),
216       };
217
218       promises.push(client.getCommunity(form));
219     } else {
220       promises.push(Promise.resolve());
221     }
222
223     return promises;
224   }
225
226   parseMessage(msg: any) {
227     const op = wsUserOp(msg);
228     console.log(msg);
229     if (msg.error) {
230       toast(i18n.t(msg.error), "danger");
231       return;
232     }
233
234     if (op === UserOperation.GetCommunity) {
235       const {
236         community_view: {
237           community: { name, id },
238         },
239       } = wsJsonToRes<GetCommunityResponse>(msg);
240
241       this.setState({
242         selectedCommunityChoice: { label: name, value: id.toString() },
243         loading: false,
244       });
245     }
246   }
247 }