]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/create-post.tsx
Adding new site setup fields. (#840)
[lemmy-ui.git] / src / shared / components / post / create-post.tsx
1 import { Either, Left, None, Option, Right, Some } from "@sniptt/monads";
2 import { Component } from "inferno";
3 import {
4   GetCommunity,
5   GetCommunityResponse,
6   GetSiteResponse,
7   ListCommunities,
8   ListCommunitiesResponse,
9   ListingType,
10   PostView,
11   SortType,
12   toOption,
13   UserOperation,
14   wsJsonToRes,
15   wsUserOp,
16 } from "lemmy-js-client";
17 import { Subscription } from "rxjs";
18 import { InitialFetchRequest, PostFormParams } from "shared/interfaces";
19 import { i18n } from "../../i18next";
20 import { UserService, WebSocketService } from "../../services";
21 import {
22   auth,
23   enableDownvotes,
24   enableNsfw,
25   fetchLimit,
26   isBrowser,
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 interface CreatePostState {
37   listCommunitiesResponse: Option<ListCommunitiesResponse>;
38   siteRes: GetSiteResponse;
39   loading: boolean;
40 }
41
42 export class CreatePost extends Component<any, CreatePostState> {
43   private isoData = setIsoData(this.context, ListCommunitiesResponse);
44   private subscription: Subscription;
45   private emptyState: CreatePostState = {
46     siteRes: this.isoData.site_res,
47     listCommunitiesResponse: None,
48     loading: true,
49   };
50
51   constructor(props: any, context: any) {
52     super(props, context);
53     this.state = this.emptyState;
54
55     this.handlePostCreate = this.handlePostCreate.bind(this);
56
57     this.parseMessage = this.parseMessage.bind(this);
58     this.subscription = wsSubscribe(this.parseMessage);
59
60     if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
61       toast(i18n.t("not_logged_in"), "danger");
62       this.context.router.history.push(`/login`);
63     }
64
65     // Only fetch the data if coming from another route
66     if (this.isoData.path == this.context.router.route.match.url) {
67       this.state = {
68         ...this.state,
69         listCommunitiesResponse: Some(
70           this.isoData.routeData[0] as ListCommunitiesResponse
71         ),
72         loading: false,
73       };
74     } else {
75       this.refetch();
76     }
77   }
78
79   refetch() {
80     this.params.nameOrId.match({
81       some: opt =>
82         opt.match({
83           left: name => {
84             let form = new GetCommunity({
85               name: Some(name),
86               id: None,
87               auth: auth(false).ok(),
88             });
89             WebSocketService.Instance.send(wsClient.getCommunity(form));
90           },
91           right: id => {
92             let form = new GetCommunity({
93               id: Some(id),
94               name: None,
95               auth: auth(false).ok(),
96             });
97             WebSocketService.Instance.send(wsClient.getCommunity(form));
98           },
99         }),
100       none: () => {
101         let listCommunitiesForm = new ListCommunities({
102           type_: Some(ListingType.All),
103           sort: Some(SortType.TopAll),
104           limit: Some(fetchLimit),
105           page: None,
106           auth: auth(false).ok(),
107         });
108         WebSocketService.Instance.send(
109           wsClient.listCommunities(listCommunitiesForm)
110         );
111       },
112     });
113   }
114
115   componentWillUnmount() {
116     if (isBrowser()) {
117       this.subscription.unsubscribe();
118     }
119   }
120
121   get documentTitle(): string {
122     return `${i18n.t("create_post")} - ${
123       this.state.siteRes.site_view.site.name
124     }`;
125   }
126
127   render() {
128     return (
129       <div className="container-lg">
130         <HtmlTags
131           title={this.documentTitle}
132           path={this.context.router.route.match.url}
133           description={None}
134           image={None}
135         />
136         {this.state.loading ? (
137           <h5>
138             <Spinner large />
139           </h5>
140         ) : (
141           this.state.listCommunitiesResponse.match({
142             some: res => (
143               <div className="row">
144                 <div className="col-12 col-lg-6 offset-lg-3 mb-4">
145                   <h5>{i18n.t("create_post")}</h5>
146                   <PostForm
147                     post_view={None}
148                     communities={Some(res.communities)}
149                     onCreate={this.handlePostCreate}
150                     params={Some(this.params)}
151                     enableDownvotes={enableDownvotes(this.state.siteRes)}
152                     enableNsfw={enableNsfw(this.state.siteRes)}
153                     allLanguages={this.state.siteRes.all_languages}
154                   />
155                 </div>
156               </div>
157             ),
158             none: <></>,
159           })
160         )}
161       </div>
162     );
163   }
164
165   get params(): PostFormParams {
166     let urlParams = new URLSearchParams(this.props.location.search);
167     let name = toOption(urlParams.get("community_name")).or(
168       this.prevCommunityName
169     );
170     let id = toOption(urlParams.get("community_id"))
171       .map(Number)
172       .or(this.prevCommunityId);
173     let nameOrId: Option<Either<string, number>>;
174     if (name.isSome()) {
175       nameOrId = Some(Left(name.unwrap()));
176     } else if (id.isSome()) {
177       nameOrId = Some(Right(id.unwrap()));
178     } else {
179       nameOrId = None;
180     }
181
182     let params: PostFormParams = {
183       name: toOption(urlParams.get("title")),
184       nameOrId,
185       body: toOption(urlParams.get("body")),
186       url: toOption(urlParams.get("url")),
187     };
188
189     return params;
190   }
191
192   get prevCommunityName(): Option<string> {
193     if (this.props.match.params.name) {
194       return toOption(this.props.match.params.name);
195     } else if (this.props.location.state) {
196       let lastLocation = this.props.location.state.prevPath;
197       if (lastLocation.includes("/c/")) {
198         return toOption(lastLocation.split("/c/")[1]);
199       }
200     }
201     return None;
202   }
203
204   get prevCommunityId(): Option<number> {
205     if (this.props.match.params.id) {
206       return toOption(this.props.match.params.id);
207     }
208     return None;
209   }
210
211   handlePostCreate(post_view: PostView) {
212     this.props.history.push(`/post/${post_view.post.id}`);
213   }
214
215   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
216     let listCommunitiesForm = new ListCommunities({
217       type_: Some(ListingType.All),
218       sort: Some(SortType.TopAll),
219       limit: Some(fetchLimit),
220       page: None,
221       auth: req.auth,
222     });
223     return [req.client.listCommunities(listCommunitiesForm)];
224   }
225
226   parseMessage(msg: any) {
227     let op = wsUserOp(msg);
228     console.log(msg);
229     if (msg.error) {
230       toast(i18n.t(msg.error), "danger");
231       return;
232     } else if (op == UserOperation.ListCommunities) {
233       let data = wsJsonToRes<ListCommunitiesResponse>(
234         msg,
235         ListCommunitiesResponse
236       );
237       this.setState({ listCommunitiesResponse: Some(data), loading: false });
238     } else if (op == UserOperation.GetCommunity) {
239       let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
240       this.setState({
241         listCommunitiesResponse: Some({
242           communities: [data.community_view],
243         }),
244         loading: false,
245       });
246     }
247   }
248 }