1 import { Component, InfernoNode, linkEvent } from "inferno";
4 CreatePrivateMessageReport,
7 MarkPrivateMessageAsRead,
10 } from "lemmy-js-client";
11 import { i18n } from "../../i18next";
12 import { UserService } from "../../services";
13 import { mdToHtml, myAuthRequired } from "../../utils";
14 import { Icon, Spinner } from "../common/icon";
15 import { MomentTime } from "../common/moment-time";
16 import { PersonListing } from "../person/person-listing";
17 import { PrivateMessageForm } from "./private-message-form";
19 interface PrivateMessageState {
24 showReportDialog: boolean;
25 reportReason?: string;
26 deleteLoading: boolean;
28 reportLoading: boolean;
31 interface PrivateMessageProps {
32 private_message_view: PrivateMessageView;
33 onDelete(form: DeletePrivateMessage): void;
34 onMarkRead(form: MarkPrivateMessageAsRead): void;
35 onReport(form: CreatePrivateMessageReport): void;
36 onCreate(form: CreatePrivateMessage): void;
37 onEdit(form: EditPrivateMessage): void;
40 export class PrivateMessage extends Component<
44 state: PrivateMessageState = {
49 showReportDialog: false,
55 constructor(props: any, context: any) {
56 super(props, context);
57 this.handleReplyCancel = this.handleReplyCancel.bind(this);
62 UserService.Instance.myUserInfo?.local_user_view.person.id ==
63 this.props.private_message_view.creator.id
67 componentWillReceiveProps(
68 nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageProps>
70 if (this.props != nextProps) {
76 showReportDialog: false,
85 const message_view = this.props.private_message_view;
86 const otherPerson: Person = this.mine
87 ? message_view.recipient
88 : message_view.creator;
91 <div className="border-top border-light">
93 <ul className="list-inline mb-0 text-muted small">
94 {/* TODO refactor this */}
95 <li className="list-inline-item">
96 {this.mine ? i18n.t("to") : i18n.t("from")}
98 <li className="list-inline-item">
99 <PersonListing person={otherPerson} />
101 <li className="list-inline-item">
104 published={message_view.private_message.published}
105 updated={message_view.private_message.updated}
109 <li className="list-inline-item">
112 className="pointer text-monospace"
113 onClick={linkEvent(this, this.handleMessageCollapse)}
115 {this.state.collapsed ? (
116 <Icon icon="plus-square" classes="icon-inline" />
118 <Icon icon="minus-square" classes="icon-inline" />
123 {this.state.showEdit && (
125 recipient={otherPerson}
126 privateMessageView={message_view}
127 onEdit={this.props.onEdit}
128 onCancel={this.handleReplyCancel}
131 {!this.state.showEdit && !this.state.collapsed && (
133 {this.state.viewSource ? (
134 <pre>{this.messageUnlessRemoved}</pre>
138 dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
141 <ul className="list-inline mb-0 text-muted font-weight-bold">
144 <li className="list-inline-item">
146 className="btn btn-link btn-animate text-muted"
147 onClick={linkEvent(this, this.handleMarkRead)}
149 message_view.private_message.read
150 ? i18n.t("mark_as_unread")
151 : i18n.t("mark_as_read")
154 message_view.private_message.read
155 ? i18n.t("mark_as_unread")
156 : i18n.t("mark_as_read")
159 {this.state.readLoading ? (
164 classes={`icon-inline ${
165 message_view.private_message.read &&
172 <li className="list-inline-item">{this.reportButton}</li>
173 <li className="list-inline-item">
175 className="btn btn-link btn-animate text-muted"
176 onClick={linkEvent(this, this.handleReplyClick)}
177 data-tippy-content={i18n.t("reply")}
178 aria-label={i18n.t("reply")}
180 <Icon icon="reply1" classes="icon-inline" />
187 <li className="list-inline-item">
189 className="btn btn-link btn-animate text-muted"
190 onClick={linkEvent(this, this.handleEditClick)}
191 data-tippy-content={i18n.t("edit")}
192 aria-label={i18n.t("edit")}
194 <Icon icon="edit" classes="icon-inline" />
197 <li className="list-inline-item">
199 className="btn btn-link btn-animate text-muted"
200 onClick={linkEvent(this, this.handleDeleteClick)}
202 !message_view.private_message.deleted
207 !message_view.private_message.deleted
212 {this.state.deleteLoading ? (
217 classes={`icon-inline ${
218 message_view.private_message.deleted &&
227 <li className="list-inline-item">
229 className="btn btn-link btn-animate text-muted"
230 onClick={linkEvent(this, this.handleViewSource)}
231 data-tippy-content={i18n.t("view_source")}
232 aria-label={i18n.t("view_source")}
236 classes={`icon-inline ${
237 this.state.viewSource && "text-success"
246 {this.state.showReportDialog && (
248 className="form-inline"
249 onSubmit={linkEvent(this, this.handleReportSubmit)}
251 <label className="sr-only" htmlFor="pm-report-reason">
256 id="pm-report-reason"
257 className="form-control mr-2"
258 placeholder={i18n.t("reason")}
260 value={this.state.reportReason}
261 onInput={linkEvent(this, this.handleReportReasonChange)}
265 className="btn btn-secondary"
266 aria-label={i18n.t("create_report")}
268 {this.state.reportLoading ? <Spinner /> : i18n.t("create_report")}
272 {this.state.showReply && (
274 recipient={otherPerson}
275 onCreate={this.props.onCreate}
278 {/* A collapsed clearfix */}
279 {this.state.collapsed && <div className="row col-12"></div>}
287 className="btn btn-link btn-animate text-muted py-0"
288 onClick={linkEvent(this, this.handleShowReportDialog)}
289 data-tippy-content={i18n.t("show_report_dialog")}
290 aria-label={i18n.t("show_report_dialog")}
292 <Icon icon="flag" inline />
297 get messageUnlessRemoved(): string {
298 const message = this.props.private_message_view.private_message;
299 return message.deleted ? `*${i18n.t("deleted")}*` : message.content;
302 handleReplyClick(i: PrivateMessage) {
303 i.setState({ showReply: true });
306 handleEditClick(i: PrivateMessage) {
307 i.setState({ showEdit: true });
311 handleDeleteClick(i: PrivateMessage) {
312 i.setState({ deleteLoading: true });
314 private_message_id: i.props.private_message_view.private_message.id,
315 deleted: !i.props.private_message_view.private_message.deleted,
316 auth: myAuthRequired(),
320 handleReplyCancel() {
321 this.setState({ showReply: false, showEdit: false });
324 handleMarkRead(i: PrivateMessage) {
325 i.setState({ readLoading: true });
327 private_message_id: i.props.private_message_view.private_message.id,
328 read: !i.props.private_message_view.private_message.read,
329 auth: myAuthRequired(),
333 handleMessageCollapse(i: PrivateMessage) {
334 i.setState({ collapsed: !i.state.collapsed });
337 handleViewSource(i: PrivateMessage) {
338 i.setState({ viewSource: !i.state.viewSource });
341 handleShowReportDialog(i: PrivateMessage) {
342 i.setState({ showReportDialog: !i.state.showReportDialog });
345 handleReportReasonChange(i: PrivateMessage, event: any) {
346 i.setState({ reportReason: event.target.value });
349 handleReportSubmit(i: PrivateMessage, event: any) {
350 event.preventDefault();
351 i.setState({ reportLoading: true });
353 private_message_id: i.props.private_message_view.private_message.id,
354 reason: i.state.reportReason ?? "",
355 auth: myAuthRequired(),