1 import { Component, linkEvent } from "inferno";
2 import { Prompt } from "inferno-router";
9 } from "lemmy-js-client";
10 import { Subscription } from "rxjs";
11 import { i18n } from "../../i18next";
12 import { UserService, WebSocketService } from "../../services";
15 capitalizeFirstLetter,
22 import { Icon, Spinner } from "../common/icon";
23 import { ImageUploadForm } from "../common/image-upload-form";
24 import { MarkdownTextArea } from "../common/markdown-textarea";
26 interface CommunityFormProps {
27 community_view?: CommunityView; // If a community is given, that means this is an edit
29 onCreate?(community: CommunityView): any;
30 onEdit?(community: CommunityView): any;
34 interface CommunityFormState {
35 communityForm: CreateCommunity;
39 export class CommunityForm extends Component<
43 private id = `community-form-${randomStr()}`;
44 private subscription: Subscription;
46 private emptyState: CommunityFormState = {
53 posting_restricted_to_mods: false,
54 auth: authField(false),
59 constructor(props: any, context: any) {
60 super(props, context);
62 this.state = this.emptyState;
64 this.handleCommunityDescriptionChange =
65 this.handleCommunityDescriptionChange.bind(this);
67 this.handleIconUpload = this.handleIconUpload.bind(this);
68 this.handleIconRemove = this.handleIconRemove.bind(this);
70 this.handleBannerUpload = this.handleBannerUpload.bind(this);
71 this.handleBannerRemove = this.handleBannerRemove.bind(this);
73 let cv = this.props.community_view;
75 this.state.communityForm = {
76 name: cv.community.name,
77 title: cv.community.title,
78 description: cv.community.description,
79 nsfw: cv.community.nsfw,
80 icon: cv.community.icon,
81 banner: cv.community.banner,
82 posting_restricted_to_mods: cv.community.posting_restricted_to_mods,
87 this.parseMessage = this.parseMessage.bind(this);
88 this.subscription = wsSubscribe(this.parseMessage);
91 // TODO this should be checked out
92 componentDidUpdate() {
94 !this.state.loading &&
95 (this.state.communityForm.name ||
96 this.state.communityForm.title ||
97 this.state.communityForm.description)
99 window.onbeforeunload = () => true;
101 window.onbeforeunload = undefined;
105 componentWillUnmount() {
106 this.subscription.unsubscribe();
107 window.onbeforeunload = null;
115 !this.state.loading &&
116 (this.state.communityForm.name ||
117 this.state.communityForm.title ||
118 this.state.communityForm.description)
120 message={i18n.t("block_leaving")}
122 <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
123 {!this.props.community_view && (
124 <div class="form-group row">
126 class="col-12 col-sm-2 col-form-label"
127 htmlFor="community-name"
131 class="position-absolute pointer unselectable ml-2 text-muted"
132 data-tippy-content={i18n.t("name_explain")}
134 <Icon icon="help-circle" classes="icon-inline" />
137 <div class="col-12 col-sm-10">
142 value={this.state.communityForm.name}
143 onInput={linkEvent(this, this.handleCommunityNameChange)}
147 title={i18n.t("community_reqs")}
152 <div class="form-group row">
154 class="col-12 col-sm-2 col-form-label"
155 htmlFor="community-title"
157 {i18n.t("display_name")}
159 class="position-absolute pointer unselectable ml-2 text-muted"
160 data-tippy-content={i18n.t("display_name_explain")}
162 <Icon icon="help-circle" classes="icon-inline" />
165 <div class="col-12 col-sm-10">
169 value={this.state.communityForm.title}
170 onInput={linkEvent(this, this.handleCommunityTitleChange)}
178 <div class="form-group row">
179 <label class="col-12 col-sm-2">{i18n.t("icon")}</label>
180 <div class="col-12 col-sm-10">
182 uploadTitle={i18n.t("upload_icon")}
183 imageSrc={this.state.communityForm.icon}
184 onUpload={this.handleIconUpload}
185 onRemove={this.handleIconRemove}
190 <div class="form-group row">
191 <label class="col-12 col-sm-2">{i18n.t("banner")}</label>
192 <div class="col-12 col-sm-10">
194 uploadTitle={i18n.t("upload_banner")}
195 imageSrc={this.state.communityForm.banner}
196 onUpload={this.handleBannerUpload}
197 onRemove={this.handleBannerRemove}
201 <div class="form-group row">
202 <label class="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
205 <div class="col-12 col-sm-10">
207 initialContent={this.state.communityForm.description}
208 onContentChange={this.handleCommunityDescriptionChange}
213 {this.props.enableNsfw && (
214 <div class="form-group row">
215 <legend class="col-form-label col-sm-2 pt-0">
219 <div class="form-check">
221 class="form-check-input position-static"
224 checked={this.state.communityForm.nsfw}
225 onChange={linkEvent(this, this.handleCommunityNsfwChange)}
231 <div class="form-group row">
232 <legend class="col-form-label col-6 pt-0">
233 {i18n.t("only_mods_can_post_in_community")}
236 <div class="form-check">
238 class="form-check-input position-static"
239 id="community-only-mods-can-post"
241 checked={this.state.communityForm.posting_restricted_to_mods}
244 this.handleCommunityPostingRestrictedToMods
250 <div class="form-group row">
254 class="btn btn-secondary mr-2"
255 disabled={this.state.loading}
257 {this.state.loading ? (
259 ) : this.props.community_view ? (
260 capitalizeFirstLetter(i18n.t("save"))
262 capitalizeFirstLetter(i18n.t("create"))
265 {this.props.community_view && (
268 class="btn btn-secondary"
269 onClick={linkEvent(this, this.handleCancel)}
281 handleCreateCommunitySubmit(i: CommunityForm, event: any) {
282 event.preventDefault();
283 i.state.loading = true;
284 if (i.props.community_view) {
285 let form: EditCommunity = {
286 ...i.state.communityForm,
287 community_id: i.props.community_view.community.id,
289 WebSocketService.Instance.send(wsClient.editCommunity(form));
291 WebSocketService.Instance.send(
292 wsClient.createCommunity(i.state.communityForm)
298 handleCommunityNameChange(i: CommunityForm, event: any) {
299 i.state.communityForm.name = event.target.value;
303 handleCommunityTitleChange(i: CommunityForm, event: any) {
304 i.state.communityForm.title = event.target.value;
308 handleCommunityDescriptionChange(val: string) {
309 this.state.communityForm.description = val;
310 this.setState(this.state);
313 handleCommunityNsfwChange(i: CommunityForm, event: any) {
314 i.state.communityForm.nsfw = event.target.checked;
318 handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
319 i.state.communityForm.posting_restricted_to_mods = event.target.checked;
323 handleCancel(i: CommunityForm) {
327 handleIconUpload(url: string) {
328 this.state.communityForm.icon = url;
329 this.setState(this.state);
333 this.state.communityForm.icon = "";
334 this.setState(this.state);
337 handleBannerUpload(url: string) {
338 this.state.communityForm.banner = url;
339 this.setState(this.state);
342 handleBannerRemove() {
343 this.state.communityForm.banner = "";
344 this.setState(this.state);
347 parseMessage(msg: any) {
348 let op = wsUserOp(msg);
351 // Errors handled by top level pages
352 // toast(i18n.t(msg.error), "danger");
353 this.state.loading = false;
354 this.setState(this.state);
356 } else if (op == UserOperation.CreateCommunity) {
357 let data = wsJsonToRes<CommunityResponse>(msg).data;
358 this.state.loading = false;
359 this.props.onCreate(data.community_view);
362 let community = data.community_view.community;
363 let person = UserService.Instance.myUserInfo.local_user_view.person;
364 UserService.Instance.myUserInfo.follows.push({
368 UserService.Instance.myUserInfo.moderates.push({
372 } else if (op == UserOperation.EditCommunity) {
373 let data = wsJsonToRes<CommunityResponse>(msg).data;
374 this.state.loading = false;
375 this.props.onEdit(data.community_view);
376 let community = data.community_view.community;
378 let followFound = UserService.Instance.myUserInfo.follows.findIndex(
379 f => f.community.id == community.id
382 UserService.Instance.myUserInfo.follows[followFound].community =
386 let moderatesFound = UserService.Instance.myUserInfo.moderates.findIndex(
387 f => f.community.id == community.id
389 if (moderatesFound) {
390 UserService.Instance.myUserInfo.moderates[moderatesFound].community =