1 import { None, Option, Some } from "@sniptt/monads/build";
2 import { Component, linkEvent } from "inferno";
4 CreatePrivateMessageReport,
6 MarkPrivateMessageAsRead,
10 } from "lemmy-js-client";
11 import { i18n } from "../../i18next";
12 import { UserService, WebSocketService } from "../../services";
13 import { auth, mdToHtml, toast, wsClient } from "../../utils";
14 import { Icon } 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: Option<string>;
28 interface PrivateMessageProps {
29 private_message_view: PrivateMessageView;
32 export class PrivateMessage extends Component<
36 private emptyState: PrivateMessageState = {
41 showReportDialog: false,
45 constructor(props: any, context: any) {
46 super(props, context);
48 this.state = this.emptyState;
49 this.handleReplyCancel = this.handleReplyCancel.bind(this);
50 this.handlePrivateMessageCreate =
51 this.handlePrivateMessageCreate.bind(this);
52 this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
56 return UserService.Instance.myUserInfo
59 m.local_user_view.person.id ==
60 this.props.private_message_view.creator.id
66 let message_view = this.props.private_message_view;
67 let otherPerson: PersonSafe = this.mine
68 ? message_view.recipient
69 : message_view.creator;
72 <div className="border-top border-light">
74 <ul className="list-inline mb-0 text-muted small">
75 {/* TODO refactor this */}
76 <li className="list-inline-item">
77 {this.mine ? i18n.t("to") : i18n.t("from")}
79 <li className="list-inline-item">
80 <PersonListing person={otherPerson} />
82 <li className="list-inline-item">
85 published={message_view.private_message.published}
86 updated={message_view.private_message.updated}
90 <li className="list-inline-item">
93 className="pointer text-monospace"
94 onClick={linkEvent(this, this.handleMessageCollapse)}
96 {this.state.collapsed ? (
97 <Icon icon="plus-square" classes="icon-inline" />
99 <Icon icon="minus-square" classes="icon-inline" />
104 {this.state.showEdit && (
106 recipient={otherPerson}
107 privateMessageView={Some(message_view)}
108 onEdit={this.handlePrivateMessageEdit}
109 onCreate={this.handlePrivateMessageCreate}
110 onCancel={this.handleReplyCancel}
113 {!this.state.showEdit && !this.state.collapsed && (
115 {this.state.viewSource ? (
116 <pre>{this.messageUnlessRemoved}</pre>
120 dangerouslySetInnerHTML={mdToHtml(this.messageUnlessRemoved)}
123 <ul className="list-inline mb-0 text-muted font-weight-bold">
126 <li className="list-inline-item">
128 className="btn btn-link btn-animate text-muted"
129 onClick={linkEvent(this, this.handleMarkRead)}
131 message_view.private_message.read
132 ? i18n.t("mark_as_unread")
133 : i18n.t("mark_as_read")
136 message_view.private_message.read
137 ? i18n.t("mark_as_unread")
138 : i18n.t("mark_as_read")
143 classes={`icon-inline ${
144 message_view.private_message.read && "text-success"
149 <li className="list-inline-item">{this.reportButton}</li>
150 <li className="list-inline-item">
152 className="btn btn-link btn-animate text-muted"
153 onClick={linkEvent(this, this.handleReplyClick)}
154 data-tippy-content={i18n.t("reply")}
155 aria-label={i18n.t("reply")}
157 <Icon icon="reply1" classes="icon-inline" />
164 <li className="list-inline-item">
166 className="btn btn-link btn-animate text-muted"
167 onClick={linkEvent(this, this.handleEditClick)}
168 data-tippy-content={i18n.t("edit")}
169 aria-label={i18n.t("edit")}
171 <Icon icon="edit" classes="icon-inline" />
174 <li className="list-inline-item">
176 className="btn btn-link btn-animate text-muted"
177 onClick={linkEvent(this, this.handleDeleteClick)}
179 !message_view.private_message.deleted
184 !message_view.private_message.deleted
191 classes={`icon-inline ${
192 message_view.private_message.deleted &&
200 <li className="list-inline-item">
202 className="btn btn-link btn-animate text-muted"
203 onClick={linkEvent(this, this.handleViewSource)}
204 data-tippy-content={i18n.t("view_source")}
205 aria-label={i18n.t("view_source")}
209 classes={`icon-inline ${
210 this.state.viewSource && "text-success"
219 {this.state.showReportDialog && (
221 className="form-inline"
222 onSubmit={linkEvent(this, this.handleReportSubmit)}
224 <label className="sr-only" htmlFor="pm-report-reason">
229 id="pm-report-reason"
230 className="form-control mr-2"
231 placeholder={i18n.t("reason")}
233 value={toUndefined(this.state.reportReason)}
234 onInput={linkEvent(this, this.handleReportReasonChange)}
238 className="btn btn-secondary"
239 aria-label={i18n.t("create_report")}
241 {i18n.t("create_report")}
245 {this.state.showReply && (
247 recipient={otherPerson}
248 privateMessageView={None}
249 onCreate={this.handlePrivateMessageCreate}
252 {/* A collapsed clearfix */}
253 {this.state.collapsed && <div className="row col-12"></div>}
261 className="btn btn-link btn-animate text-muted py-0"
262 onClick={linkEvent(this, this.handleShowReportDialog)}
263 data-tippy-content={i18n.t("show_report_dialog")}
264 aria-label={i18n.t("show_report_dialog")}
266 <Icon icon="flag" inline />
271 get messageUnlessRemoved(): string {
272 let message = this.props.private_message_view.private_message;
273 return message.deleted ? `*${i18n.t("deleted")}*` : message.content;
276 handleReplyClick(i: PrivateMessage) {
277 i.setState({ showReply: true });
280 handleEditClick(i: PrivateMessage) {
281 i.setState({ showEdit: true });
285 handleDeleteClick(i: PrivateMessage) {
286 let form = new DeletePrivateMessage({
287 private_message_id: i.props.private_message_view.private_message.id,
288 deleted: !i.props.private_message_view.private_message.deleted,
289 auth: auth().unwrap(),
291 WebSocketService.Instance.send(wsClient.deletePrivateMessage(form));
294 handleReplyCancel() {
295 this.setState({ showReply: false, showEdit: false });
298 handleMarkRead(i: PrivateMessage) {
299 let form = new MarkPrivateMessageAsRead({
300 private_message_id: i.props.private_message_view.private_message.id,
301 read: !i.props.private_message_view.private_message.read,
302 auth: auth().unwrap(),
304 WebSocketService.Instance.send(wsClient.markPrivateMessageAsRead(form));
307 handleMessageCollapse(i: PrivateMessage) {
308 i.setState({ collapsed: !i.state.collapsed });
311 handleViewSource(i: PrivateMessage) {
312 i.setState({ viewSource: !i.state.viewSource });
315 handleShowReportDialog(i: PrivateMessage) {
316 i.setState({ showReportDialog: !i.state.showReportDialog });
319 handleReportReasonChange(i: PrivateMessage, event: any) {
320 i.setState({ reportReason: Some(event.target.value) });
323 handleReportSubmit(i: PrivateMessage, event: any) {
324 event.preventDefault();
325 let form = new CreatePrivateMessageReport({
326 private_message_id: i.props.private_message_view.private_message.id,
327 reason: toUndefined(i.state.reportReason),
328 auth: auth().unwrap(),
330 WebSocketService.Instance.send(wsClient.createPrivateMessageReport(form));
332 i.setState({ showReportDialog: false });
335 handlePrivateMessageEdit() {
336 this.setState({ showEdit: false });
339 handlePrivateMessageCreate(message: PrivateMessageView) {
340 UserService.Instance.myUserInfo.match({
342 if (message.creator.id == mui.local_user_view.person.id) {
343 this.setState({ showReply: false });
344 toast(i18n.t("message_sent"));