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