lemmy-ui/src/shared/components/private_message/private-message-form.tsx
Alec Armbruster 043b522ff1
utils.ts organization, round two (#1427)
* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update src/shared/utils/app/convert-comment-sort-type.ts

Co-authored-by: SleeplessOne1917 <abias1122@gmail.com>

* prettier pass

---------

Co-authored-by: SleeplessOne1917 <abias1122@gmail.com>
2023-06-21 18:28:24 -04:00

205 lines
6 KiB
TypeScript

import { myAuthRequired } from "@utils/app";
import { capitalizeFirstLetter } from "@utils/helpers";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
CreatePrivateMessage,
EditPrivateMessage,
Person,
PrivateMessageView,
} from "lemmy-js-client";
import { relTags } from "../../config";
import { i18n } from "../../i18next";
import { setupTippy } from "../../tippy";
import { Icon, Spinner } from "../common/icon";
import { MarkdownTextArea } from "../common/markdown-textarea";
import NavigationPrompt from "../common/navigation-prompt";
import { PersonListing } from "../person/person-listing";
interface PrivateMessageFormProps {
recipient: Person;
privateMessageView?: PrivateMessageView; // If a pm is given, that means this is an edit
onCancel?(): any;
onCreate?(form: CreatePrivateMessage): void;
onEdit?(form: EditPrivateMessage): void;
}
interface PrivateMessageFormState {
content?: string;
loading: boolean;
previewMode: boolean;
showDisclaimer: boolean;
submitted: boolean;
}
export class PrivateMessageForm extends Component<
PrivateMessageFormProps,
PrivateMessageFormState
> {
state: PrivateMessageFormState = {
loading: false,
previewMode: false,
showDisclaimer: false,
content: this.props.privateMessageView
? this.props.privateMessageView.private_message.content
: undefined,
submitted: false,
};
constructor(props: any, context: any) {
super(props, context);
this.handleContentChange = this.handleContentChange.bind(this);
}
componentDidMount() {
setupTippy();
}
componentWillReceiveProps(
nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageFormProps>
): void {
if (this.props != nextProps) {
this.setState({ loading: false, content: undefined, previewMode: false });
}
}
// TODO
// <Prompt
// when={!this.state.loading && this.state.content}
// message={i18n.t("block_leaving")}
// />
render() {
return (
<form
className="private-message-form"
onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}
>
<NavigationPrompt
when={
!this.state.loading && !!this.state.content && !this.state.submitted
}
/>
{!this.props.privateMessageView && (
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">
{capitalizeFirstLetter(i18n.t("to"))}
</label>
<div className="col-sm-10 form-control-plaintext">
<PersonListing person={this.props.recipient} />
</div>
</div>
)}
<div className="mb-3 row">
<label className="col-sm-2 col-form-label">
{i18n.t("message")}
<button
className="btn btn-link text-warning d-inline-block"
onClick={linkEvent(this, this.handleShowDisclaimer)}
data-tippy-content={i18n.t("private_message_disclaimer")}
aria-label={i18n.t("private_message_disclaimer")}
>
<Icon icon="alert-triangle" classes="icon-inline" />
</button>
</label>
<div className="col-sm-10">
<MarkdownTextArea
initialContent={this.state.content}
onContentChange={this.handleContentChange}
allLanguages={[]}
siteLanguages={[]}
hideNavigationWarnings
/>
</div>
</div>
{this.state.showDisclaimer && (
<div className="mb-3 row">
<div className="offset-sm-2 col-sm-10">
<div className="alert alert-danger" role="alert">
<T i18nKey="private_message_disclaimer">
#
<a
className="alert-link"
rel={relTags}
href="https://element.io/get-started"
>
#
</a>
</T>
</div>
</div>
</div>
)}
<div className="mb-3 row">
<div className="offset-sm-2 col-sm-10">
<button
type="submit"
className="btn btn-secondary me-2"
disabled={this.state.loading}
>
{this.state.loading ? (
<Spinner />
) : this.props.privateMessageView ? (
capitalizeFirstLetter(i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("send_message"))
)}
</button>
{this.props.privateMessageView && (
<button
type="button"
className="btn btn-secondary"
onClick={linkEvent(this, this.handleCancel)}
>
{i18n.t("cancel")}
</button>
)}
<ul className="d-inline-block float-right list-inline mb-1 text-muted font-weight-bold">
<li className="list-inline-item"></li>
</ul>
</div>
</div>
</form>
);
}
handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
event.preventDefault();
i.setState({ loading: true, submitted: true });
const pm = i.props.privateMessageView;
const auth = myAuthRequired();
const content = i.state.content ?? "";
if (pm) {
i.props.onEdit?.({
private_message_id: pm.private_message.id,
content,
auth,
});
} else {
i.props.onCreate?.({
content,
recipient_id: i.props.recipient.id,
auth,
});
}
}
handleContentChange(val: string) {
this.setState({ content: val });
}
handleCancel(i: PrivateMessageForm) {
i.props.onCancel?.();
}
handlePreviewToggle(i: PrivateMessageForm, event: any) {
event.preventDefault();
i.setState({ previewMode: !i.state.previewMode });
}
handleShowDisclaimer(i: PrivateMessageForm) {
i.setState({ showDisclaimer: !i.state.showDisclaimer });
}
}