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