]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/create-post.tsx
Make pages use query params instead of route params where appropriate (#977)
[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 { UserService, WebSocketService } from "../../services";
16 import {
17   Choice,
18   enableDownvotes,
19   enableNsfw,
20   getIdFromString,
21   getQueryParams,
22   getQueryString,
23   isBrowser,
24   myAuth,
25   QueryParams,
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     if (!UserService.Instance.myUserInfo && isBrowser()) {
73       toast(i18n.t("not_logged_in"), "danger");
74       this.context.router.history.push(`/login`);
75     }
76
77     // Only fetch the data if coming from another route
78     if (this.isoData.path === this.context.router.route.match.url) {
79       const communityRes = this.isoData.routeData[0] as
80         | GetCommunityResponse
81         | undefined;
82
83       if (communityRes) {
84         const communityChoice: Choice = {
85           label: communityRes.community_view.community.name,
86           value: communityRes.community_view.community.id.toString(),
87         };
88
89         this.state = {
90           ...this.state,
91           selectedCommunityChoice: communityChoice,
92         };
93       }
94
95       this.state = {
96         ...this.state,
97         loading: false,
98       };
99     } else {
100       this.fetchCommunity();
101     }
102   }
103
104   fetchCommunity() {
105     const { communityId } = getCreatePostQueryParams();
106     const auth = myAuth(false);
107
108     if (communityId) {
109       const form: GetCommunity = {
110         id: communityId,
111         auth,
112       };
113
114       WebSocketService.Instance.send(wsClient.getCommunity(form));
115     }
116   }
117
118   componentDidMount(): void {
119     const { communityId } = getCreatePostQueryParams();
120
121     if (communityId?.toString() !== this.state.selectedCommunityChoice?.value) {
122       this.fetchCommunity();
123     } else if (!communityId) {
124       this.setState({
125         selectedCommunityChoice: undefined,
126         loading: false,
127       });
128     }
129   }
130
131   componentWillUnmount() {
132     if (isBrowser()) {
133       this.subscription?.unsubscribe();
134     }
135   }
136
137   get documentTitle(): string {
138     return `${i18n.t("create_post")} - ${
139       this.state.siteRes.site_view.site.name
140     }`;
141   }
142
143   render() {
144     const { selectedCommunityChoice } = this.state;
145
146     const locationState = this.props.history.location.state as
147       | PostFormParams
148       | undefined;
149
150     return (
151       <div className="container-lg">
152         <HtmlTags
153           title={this.documentTitle}
154           path={this.context.router.route.match.url}
155         />
156         {this.state.loading ? (
157           <h5>
158             <Spinner large />
159           </h5>
160         ) : (
161           <div className="row">
162             <div className="col-12 col-lg-6 offset-lg-3 mb-4">
163               <h5>{i18n.t("create_post")}</h5>
164               <PostForm
165                 onCreate={this.handlePostCreate}
166                 params={locationState}
167                 enableDownvotes={enableDownvotes(this.state.siteRes)}
168                 enableNsfw={enableNsfw(this.state.siteRes)}
169                 allLanguages={this.state.siteRes.all_languages}
170                 siteLanguages={this.state.siteRes.discussion_languages}
171                 selectedCommunityChoice={selectedCommunityChoice}
172                 onSelectCommunity={this.handleSelectedCommunityChange}
173               />
174             </div>
175           </div>
176         )}
177       </div>
178     );
179   }
180
181   updateUrl({ communityId }: Partial<CreatePostProps>) {
182     const { communityId: urlCommunityId } = getCreatePostQueryParams();
183
184     const queryParams: QueryParams<CreatePostProps> = {
185       communityId: (communityId ?? urlCommunityId)?.toString(),
186     };
187
188     const locationState = this.props.history.location.state as
189       | PostFormParams
190       | undefined;
191
192     this.props.history.push(
193       `/create_post${getQueryString(queryParams)}`,
194       locationState
195     );
196
197     this.fetchCommunity();
198   }
199
200   handleSelectedCommunityChange(choice: Choice) {
201     this.updateUrl({
202       communityId: getIdFromString(choice?.value),
203     });
204   }
205
206   handlePostCreate(post_view: PostView) {
207     this.props.history.replace(`/post/${post_view.post.id}`);
208   }
209
210   static fetchInitialData({
211     client,
212     query: { communityId },
213     auth,
214   }: InitialFetchRequest<QueryParams<CreatePostProps>>): Promise<any>[] {
215     const promises: Promise<any>[] = [];
216
217     if (communityId) {
218       const form: GetCommunity = {
219         auth,
220         id: getIdFromString(communityId),
221       };
222
223       promises.push(client.getCommunity(form));
224     } else {
225       promises.push(Promise.resolve());
226     }
227
228     return promises;
229   }
230
231   parseMessage(msg: any) {
232     const op = wsUserOp(msg);
233     console.log(msg);
234     if (msg.error) {
235       toast(i18n.t(msg.error), "danger");
236       return;
237     }
238
239     if (op === UserOperation.GetCommunity) {
240       const {
241         community_view: {
242           community: { name, id },
243         },
244       } = wsJsonToRes<GetCommunityResponse>(msg);
245
246       this.setState({
247         selectedCommunityChoice: { label: name, value: id.toString() },
248         loading: false,
249       });
250     }
251   }
252 }