1 import { Component, linkEvent } from "inferno";
2 import { Link } from "inferno-router";
5 CommunityModeratorView,
11 } from "lemmy-js-client";
12 import { i18n } from "../../i18next";
13 import { UserService, WebSocketService } from "../../services";
21 import { BannerIconHeader } from "../common/banner-icon-header";
22 import { Icon } from "../common/icon";
23 import { CommunityForm } from "../community/community-form";
24 import { CommunityLink } from "../community/community-link";
25 import { PersonListing } from "../person/person-listing";
27 interface SidebarProps {
28 community_view: CommunityView;
29 moderators: CommunityModeratorView[];
30 admins: PersonViewSafe[];
36 interface SidebarState {
38 showRemoveDialog: boolean;
40 removeExpires: string;
41 showConfirmLeaveModTeam: boolean;
44 export class Sidebar extends Component<SidebarProps, SidebarState> {
45 private emptyState: SidebarState = {
47 showRemoveDialog: false,
50 showConfirmLeaveModTeam: false,
53 constructor(props: any, context: any) {
54 super(props, context);
55 this.state = this.emptyState;
56 this.handleEditCommunity = this.handleEditCommunity.bind(this);
57 this.handleEditCancel = this.handleEditCancel.bind(this);
63 {!this.state.showEdit ? (
67 community_view={this.props.community_view}
68 onEdit={this.handleEditCommunity}
69 onCancel={this.handleEditCancel}
70 enableNsfw={this.props.enableNsfw}
80 <div class="card border-secondary mb-3">
81 <div class="card-body">
82 {this.communityTitle()}
88 <div class="card border-secondary mb-3">
89 <div class="card-body">
100 let community = this.props.community_view.community;
101 let subscribed = this.props.community_view.subscribed;
104 <h5 className="mb-0">
105 {this.props.showIcon && (
106 <BannerIconHeader icon={community.icon} banner={community.banner} />
108 <span class="mr-2">{community.title}</span>
111 class="btn btn-secondary btn-sm mr-2"
113 onClick={linkEvent(this, this.handleUnsubscribe)}
115 <Icon icon="check" classes="icon-inline text-success mr-1" />
119 {community.removed && (
120 <small className="mr-2 text-muted font-italic">
124 {community.deleted && (
125 <small className="mr-2 text-muted font-italic">
130 <small className="mr-2 text-muted font-italic">
136 community={community}
147 let community_view = this.props.community_view;
148 let counts = community_view.counts;
150 <ul class="my-1 list-inline">
151 <li className="list-inline-item badge badge-secondary">
152 {i18n.t("number_online", {
153 count: this.props.online,
154 formattedCount: numToSI(this.props.online),
158 className="list-inline-item badge badge-secondary pointer"
159 data-tippy-content={`${i18n.t("number_of_users", {
160 count: counts.users_active_day,
161 formattedCount: counts.users_active_day,
162 })} ${i18n.t("active_in_the_last")} ${i18n.t("day")}`}
164 {i18n.t("number_of_users", {
165 count: counts.users_active_day,
166 formattedCount: numToSI(counts.users_active_day),
171 className="list-inline-item badge badge-secondary pointer"
172 data-tippy-content={`${i18n.t("number_of_users", {
173 count: counts.users_active_week,
174 formattedCount: counts.users_active_week,
175 })} ${i18n.t("active_in_the_last")} ${i18n.t("week")}`}
177 {i18n.t("number_of_users", {
178 count: counts.users_active_week,
179 formattedCount: numToSI(counts.users_active_week),
184 className="list-inline-item badge badge-secondary pointer"
185 data-tippy-content={`${i18n.t("number_of_users", {
186 count: counts.users_active_month,
187 formattedCount: counts.users_active_month,
188 })} ${i18n.t("active_in_the_last")} ${i18n.t("month")}`}
190 {i18n.t("number_of_users", {
191 count: counts.users_active_month,
192 formattedCount: numToSI(counts.users_active_month),
197 className="list-inline-item badge badge-secondary pointer"
198 data-tippy-content={`${i18n.t("number_of_users", {
199 count: counts.users_active_half_year,
200 formattedCount: counts.users_active_half_year,
201 })} ${i18n.t("active_in_the_last")} ${i18n.t("number_of_months", {
206 {i18n.t("number_of_users", {
207 count: counts.users_active_half_year,
208 formattedCount: numToSI(counts.users_active_half_year),
210 / {i18n.t("number_of_months", { count: 6, formattedCount: 6 })}
212 <li className="list-inline-item badge badge-secondary">
213 {i18n.t("number_of_subscribers", {
214 count: counts.subscribers,
215 formattedCount: numToSI(counts.subscribers),
218 <li className="list-inline-item badge badge-secondary">
219 {i18n.t("number_of_posts", {
221 formattedCount: numToSI(counts.posts),
224 <li className="list-inline-item badge badge-secondary">
225 {i18n.t("number_of_comments", {
226 count: counts.comments,
227 formattedCount: numToSI(counts.comments),
230 <li className="list-inline-item">
232 className="badge badge-secondary"
233 to={`/modlog/community/${this.props.community_view.community.id}`}
244 <ul class="list-inline small">
245 <li class="list-inline-item">{i18n.t("mods")}: </li>
246 {this.props.moderators.map(mod => (
247 <li class="list-inline-item">
248 <PersonListing person={mod.moderator} />
256 let community_view = this.props.community_view;
258 community_view.subscribed && (
260 className={`btn btn-secondary btn-block mb-2 ${
261 community_view.community.deleted || community_view.community.removed
265 to={`/create_post?community_id=${community_view.community.id}`}
267 {i18n.t("create_a_post")}
274 let community_view = this.props.community_view;
277 {!community_view.subscribed && (
279 class="btn btn-secondary btn-block"
281 onClick={linkEvent(this, this.handleSubscribe)}
283 {i18n.t("subscribe")}
291 let description = this.props.community_view.community.description;
296 dangerouslySetInnerHTML={mdToHtml(description)}
303 let community_view = this.props.community_view;
306 <ul class="list-inline mb-1 text-muted font-weight-bold">
309 <li className="list-inline-item-action">
311 class="btn btn-link text-muted d-inline-block"
312 onClick={linkEvent(this, this.handleEditClick)}
313 data-tippy-content={i18n.t("edit")}
314 aria-label={i18n.t("edit")}
316 <Icon icon="edit" classes="icon-inline" />
320 (!this.state.showConfirmLeaveModTeam ? (
321 <li className="list-inline-item-action">
323 class="btn btn-link text-muted d-inline-block"
326 this.handleShowConfirmLeaveModTeamClick
329 {i18n.t("leave_mod_team")}
334 <li className="list-inline-item-action">
335 {i18n.t("are_you_sure")}
337 <li className="list-inline-item-action">
339 class="btn btn-link text-muted d-inline-block"
340 onClick={linkEvent(this, this.handleLeaveModTeamClick)}
345 <li className="list-inline-item-action">
347 class="btn btn-link text-muted d-inline-block"
350 this.handleCancelLeaveModTeamClick
359 <li className="list-inline-item-action">
361 class="btn btn-link text-muted d-inline-block"
362 onClick={linkEvent(this, this.handleDeleteClick)}
364 !community_view.community.deleted
369 !community_view.community.deleted
376 classes={`icon-inline ${
377 community_view.community.deleted && "text-danger"
386 <li className="list-inline-item">
387 {!this.props.community_view.community.removed ? (
389 class="btn btn-link text-muted d-inline-block"
390 onClick={linkEvent(this, this.handleModRemoveShow)}
396 class="btn btn-link text-muted d-inline-block"
397 onClick={linkEvent(this, this.handleModRemoveSubmit)}
405 {this.state.showRemoveDialog && (
406 <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
407 <div class="form-group row">
408 <label class="col-form-label" htmlFor="remove-reason">
414 class="form-control mr-2"
415 placeholder={i18n.t("optional")}
416 value={this.state.removeReason}
417 onInput={linkEvent(this, this.handleModRemoveReasonChange)}
420 {/* TODO hold off on expires for now */}
421 {/* <div class="form-group row"> */}
422 {/* <label class="col-form-label">Expires</label> */}
423 {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
425 <div class="form-group row">
426 <button type="submit" class="btn btn-secondary">
427 {i18n.t("remove_community")}
436 handleEditClick(i: Sidebar) {
437 i.state.showEdit = true;
441 handleEditCommunity() {
442 this.state.showEdit = false;
443 this.setState(this.state);
447 this.state.showEdit = false;
448 this.setState(this.state);
451 handleDeleteClick(i: Sidebar, event: any) {
452 event.preventDefault();
453 let deleteForm: DeleteCommunity = {
454 community_id: i.props.community_view.community.id,
455 deleted: !i.props.community_view.community.deleted,
458 WebSocketService.Instance.send(wsClient.deleteCommunity(deleteForm));
461 handleShowConfirmLeaveModTeamClick(i: Sidebar) {
462 i.state.showConfirmLeaveModTeam = true;
466 handleLeaveModTeamClick(i: Sidebar) {
467 let form: AddModToCommunity = {
468 person_id: UserService.Instance.myUserInfo.local_user_view.person.id,
469 community_id: i.props.community_view.community.id,
473 WebSocketService.Instance.send(wsClient.addModToCommunity(form));
474 i.state.showConfirmLeaveModTeam = false;
478 handleCancelLeaveModTeamClick(i: Sidebar) {
479 i.state.showConfirmLeaveModTeam = false;
483 handleUnsubscribe(i: Sidebar, event: any) {
484 event.preventDefault();
485 let community_id = i.props.community_view.community.id;
486 let form: FollowCommunity = {
491 WebSocketService.Instance.send(wsClient.followCommunity(form));
494 UserService.Instance.myUserInfo.follows =
495 UserService.Instance.myUserInfo.follows.filter(
496 i => i.community.id != community_id
500 handleSubscribe(i: Sidebar, event: any) {
501 event.preventDefault();
502 let community_id = i.props.community_view.community.id;
503 let form: FollowCommunity = {
508 WebSocketService.Instance.send(wsClient.followCommunity(form));
511 UserService.Instance.myUserInfo.follows.push({
512 community: i.props.community_view.community,
513 follower: UserService.Instance.myUserInfo.local_user_view.person,
517 private get amTopMod(): boolean {
519 this.props.moderators[0].moderator.id ==
520 UserService.Instance.myUserInfo.local_user_view.person.id
524 get canMod(): boolean {
526 UserService.Instance.myUserInfo &&
527 this.props.moderators
528 .map(m => m.moderator.id)
529 .includes(UserService.Instance.myUserInfo.local_user_view.person.id)
533 get canAdmin(): boolean {
535 UserService.Instance.myUserInfo &&
537 .map(a => a.person.id)
538 .includes(UserService.Instance.myUserInfo.local_user_view.person.id)
542 handleModRemoveShow(i: Sidebar) {
543 i.state.showRemoveDialog = true;
547 handleModRemoveReasonChange(i: Sidebar, event: any) {
548 i.state.removeReason = event.target.value;
552 handleModRemoveExpiresChange(i: Sidebar, event: any) {
553 console.log(event.target.value);
554 i.state.removeExpires = event.target.value;
558 handleModRemoveSubmit(i: Sidebar, event: any) {
559 event.preventDefault();
560 let removeForm: RemoveCommunity = {
561 community_id: i.props.community_view.community.id,
562 removed: !i.props.community_view.community.removed,
563 reason: i.state.removeReason,
564 expires: getUnixTime(i.state.removeExpires),
567 WebSocketService.Instance.send(wsClient.removeCommunity(removeForm));
569 i.state.showRemoveDialog = false;