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