1 import { None, Option, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import { Prompt } from "inferno-router";
13 } from "lemmy-js-client";
14 import { Subscription } from "rxjs";
15 import { i18n } from "../../i18next";
16 import { UserService, WebSocketService } from "../../services";
19 capitalizeFirstLetter,
24 import { Icon, Spinner } from "../common/icon";
25 import { ImageUploadForm } from "../common/image-upload-form";
26 import { MarkdownTextArea } from "../common/markdown-textarea";
28 interface CommunityFormProps {
29 community_view: Option<CommunityView>; // If a community is given, that means this is an edit
31 onCreate?(community: CommunityView): any;
32 onEdit?(community: CommunityView): any;
36 interface CommunityFormState {
37 communityForm: CreateCommunity;
41 export class CommunityForm extends Component<
45 private id = `community-form-${randomStr()}`;
46 private subscription: Subscription;
48 private emptyState: CommunityFormState = {
49 communityForm: new CreateCommunity({
56 posting_restricted_to_mods: None,
62 constructor(props: any, context: any) {
63 super(props, context);
65 this.state = this.emptyState;
67 this.handleCommunityDescriptionChange =
68 this.handleCommunityDescriptionChange.bind(this);
70 this.handleIconUpload = this.handleIconUpload.bind(this);
71 this.handleIconRemove = this.handleIconRemove.bind(this);
73 this.handleBannerUpload = this.handleBannerUpload.bind(this);
74 this.handleBannerRemove = this.handleBannerRemove.bind(this);
76 this.props.community_view.match({
78 this.state.communityForm = new CreateCommunity({
79 name: cv.community.name,
80 title: cv.community.title,
81 description: cv.community.description,
82 nsfw: Some(cv.community.nsfw),
83 icon: cv.community.icon,
84 banner: cv.community.banner,
85 posting_restricted_to_mods: Some(
86 cv.community.posting_restricted_to_mods
88 auth: auth().unwrap(),
94 this.parseMessage = this.parseMessage.bind(this);
95 this.subscription = wsSubscribe(this.parseMessage);
98 componentDidUpdate() {
100 !this.state.loading &&
101 (this.state.communityForm.name ||
102 this.state.communityForm.title ||
103 this.state.communityForm.description.isSome())
105 window.onbeforeunload = () => true;
107 window.onbeforeunload = undefined;
111 componentWillUnmount() {
112 this.subscription.unsubscribe();
113 window.onbeforeunload = null;
121 !this.state.loading &&
122 (this.state.communityForm.name ||
123 this.state.communityForm.title ||
124 this.state.communityForm.description.isSome())
126 message={i18n.t("block_leaving")}
128 <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
129 {this.props.community_view.isNone() && (
130 <div class="form-group row">
132 class="col-12 col-sm-2 col-form-label"
133 htmlFor="community-name"
137 class="position-absolute pointer unselectable ml-2 text-muted"
138 data-tippy-content={i18n.t("name_explain")}
140 <Icon icon="help-circle" classes="icon-inline" />
143 <div class="col-12 col-sm-10">
148 value={this.state.communityForm.name}
149 onInput={linkEvent(this, this.handleCommunityNameChange)}
153 title={i18n.t("community_reqs")}
158 <div class="form-group row">
160 class="col-12 col-sm-2 col-form-label"
161 htmlFor="community-title"
163 {i18n.t("display_name")}
165 class="position-absolute pointer unselectable ml-2 text-muted"
166 data-tippy-content={i18n.t("display_name_explain")}
168 <Icon icon="help-circle" classes="icon-inline" />
171 <div class="col-12 col-sm-10">
175 value={this.state.communityForm.title}
176 onInput={linkEvent(this, this.handleCommunityTitleChange)}
184 <div class="form-group row">
185 <label class="col-12 col-sm-2">{i18n.t("icon")}</label>
186 <div class="col-12 col-sm-10">
188 uploadTitle={i18n.t("upload_icon")}
189 imageSrc={this.state.communityForm.icon}
190 onUpload={this.handleIconUpload}
191 onRemove={this.handleIconRemove}
196 <div class="form-group row">
197 <label class="col-12 col-sm-2">{i18n.t("banner")}</label>
198 <div class="col-12 col-sm-10">
200 uploadTitle={i18n.t("upload_banner")}
201 imageSrc={this.state.communityForm.banner}
202 onUpload={this.handleBannerUpload}
203 onRemove={this.handleBannerRemove}
207 <div class="form-group row">
208 <label class="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
211 <div class="col-12 col-sm-10">
213 initialContent={this.state.communityForm.description}
214 placeholder={Some("description")}
217 onContentChange={this.handleCommunityDescriptionChange}
222 {this.props.enableNsfw && (
223 <div class="form-group row">
224 <legend class="col-form-label col-sm-2 pt-0">
228 <div class="form-check">
230 class="form-check-input position-static"
233 checked={toUndefined(this.state.communityForm.nsfw)}
234 onChange={linkEvent(this, this.handleCommunityNsfwChange)}
240 <div class="form-group row">
241 <legend class="col-form-label col-6 pt-0">
242 {i18n.t("only_mods_can_post_in_community")}
245 <div class="form-check">
247 class="form-check-input position-static"
248 id="community-only-mods-can-post"
250 checked={toUndefined(
251 this.state.communityForm.posting_restricted_to_mods
255 this.handleCommunityPostingRestrictedToMods
261 <div class="form-group row">
265 class="btn btn-secondary mr-2"
266 disabled={this.state.loading}
268 {this.state.loading ? (
270 ) : this.props.community_view.isSome() ? (
271 capitalizeFirstLetter(i18n.t("save"))
273 capitalizeFirstLetter(i18n.t("create"))
276 {this.props.community_view.isSome() && (
279 class="btn btn-secondary"
280 onClick={linkEvent(this, this.handleCancel)}
292 handleCreateCommunitySubmit(i: CommunityForm, event: any) {
293 event.preventDefault();
294 i.state.loading = true;
295 let cForm = i.state.communityForm;
297 i.props.community_view.match({
299 let form = new EditCommunity({
300 community_id: cv.community.id,
301 title: Some(cForm.title),
302 description: cForm.description,
304 banner: cForm.banner,
306 posting_restricted_to_mods: cForm.posting_restricted_to_mods,
307 auth: auth().unwrap(),
310 WebSocketService.Instance.send(wsClient.editCommunity(form));
313 WebSocketService.Instance.send(
314 wsClient.createCommunity(i.state.communityForm)
321 handleCommunityNameChange(i: CommunityForm, event: any) {
322 i.state.communityForm.name = event.target.value;
326 handleCommunityTitleChange(i: CommunityForm, event: any) {
327 i.state.communityForm.title = event.target.value;
331 handleCommunityDescriptionChange(val: string) {
332 this.state.communityForm.description = Some(val);
333 this.setState(this.state);
336 handleCommunityNsfwChange(i: CommunityForm, event: any) {
337 i.state.communityForm.nsfw = event.target.checked;
341 handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
342 i.state.communityForm.posting_restricted_to_mods = event.target.checked;
346 handleCancel(i: CommunityForm) {
350 handleIconUpload(url: string) {
351 this.state.communityForm.icon = Some(url);
352 this.setState(this.state);
356 this.state.communityForm.icon = Some("");
357 this.setState(this.state);
360 handleBannerUpload(url: string) {
361 this.state.communityForm.banner = Some(url);
362 this.setState(this.state);
365 handleBannerRemove() {
366 this.state.communityForm.banner = Some("");
367 this.setState(this.state);
370 parseMessage(msg: any) {
371 let op = wsUserOp(msg);
374 // Errors handled by top level pages
375 // toast(i18n.t(msg.error), "danger");
376 this.state.loading = false;
377 this.setState(this.state);
379 } else if (op == UserOperation.CreateCommunity) {
380 let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
381 this.state.loading = false;
382 this.props.onCreate(data.community_view);
385 let community = data.community_view.community;
387 UserService.Instance.myUserInfo.match({
389 let person = mui.local_user_view.person;
401 } else if (op == UserOperation.EditCommunity) {
402 let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
403 this.state.loading = false;
404 this.props.onEdit(data.community_view);
405 let community = data.community_view.community;
407 UserService.Instance.myUserInfo.match({
409 let followFound = mui.follows.findIndex(
410 f => f.community.id == community.id
413 mui.follows[followFound].community = community;
416 let moderatesFound = mui.moderates.findIndex(
417 f => f.community.id == community.id
419 if (moderatesFound) {
420 mui.moderates[moderatesFound].community = community;