mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-22 04:11:12 +00:00
Fix some submit button issues (#2487)
* Prevent PostForm submit button spam * Keep CreatePost PostForm visible during submission * Keep PostListing PostForm visible during submission * Keep PostForm navigation warning enabled during submission * Remove `finished` from MarkdownTextAreaProps * Handle CommentForm submission failures * Keep CommentForm navigation warning enabled during submission * Handle PrivateMessageForm submission failures * Bypass navigation warning for successful CreatePrivateMessage * Fix absolute import, add eslint rule * Cleaner handleCommentSubmit --------- Co-authored-by: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com>
This commit is contained in:
parent
14ae45fe95
commit
02fcfa26ee
19 changed files with 270 additions and 251 deletions
|
@ -79,6 +79,17 @@ export default [
|
||||||
"unicorn/filename-case": 0,
|
"unicorn/filename-case": 0,
|
||||||
"jsx-a11y/media-has-caption": 0,
|
"jsx-a11y/media-has-caption": 0,
|
||||||
"jsx-a11y/label-has-associated-control": 0,
|
"jsx-a11y/label-has-associated-control": 0,
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
group: ["assets/*", "client/*", "server/*", "shared/*"],
|
||||||
|
message: "Use relative import instead.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -2,18 +2,23 @@ import { capitalizeFirstLetter } from "@utils/helpers";
|
||||||
import { Component } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { T } from "inferno-i18next-dess";
|
import { T } from "inferno-i18next-dess";
|
||||||
import { Link } from "inferno-router";
|
import { Link } from "inferno-router";
|
||||||
import { CreateComment, EditComment, Language } from "lemmy-js-client";
|
import {
|
||||||
|
CommentResponse,
|
||||||
|
CreateComment,
|
||||||
|
EditComment,
|
||||||
|
Language,
|
||||||
|
} from "lemmy-js-client";
|
||||||
import { CommentNodeI } from "../../interfaces";
|
import { CommentNodeI } from "../../interfaces";
|
||||||
import { I18NextService, UserService } from "../../services";
|
import { I18NextService, UserService } from "../../services";
|
||||||
import { Icon } from "../common/icon";
|
import { Icon } from "../common/icon";
|
||||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||||
|
import { RequestState } from "../../services/HttpService";
|
||||||
|
|
||||||
interface CommentFormProps {
|
interface CommentFormProps {
|
||||||
/**
|
/**
|
||||||
* Can either be the parent, or the editable comment. The right side is a postId.
|
* Can either be the parent, or the editable comment. The right side is a postId.
|
||||||
*/
|
*/
|
||||||
node: CommentNodeI | number;
|
node: CommentNodeI | number;
|
||||||
finished?: boolean;
|
|
||||||
edit?: boolean;
|
edit?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
focus?: boolean;
|
focus?: boolean;
|
||||||
|
@ -21,7 +26,9 @@ interface CommentFormProps {
|
||||||
allLanguages: Language[];
|
allLanguages: Language[];
|
||||||
siteLanguages: number[];
|
siteLanguages: number[];
|
||||||
containerClass?: string;
|
containerClass?: string;
|
||||||
onUpsertComment(form: EditComment | CreateComment): void;
|
onUpsertComment(
|
||||||
|
form: EditComment | CreateComment,
|
||||||
|
): Promise<RequestState<CommentResponse>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CommentForm extends Component<CommentFormProps, any> {
|
export class CommentForm extends Component<CommentFormProps, any> {
|
||||||
|
@ -50,7 +57,6 @@ export class CommentForm extends Component<CommentFormProps, any> {
|
||||||
initialContent={initialContent}
|
initialContent={initialContent}
|
||||||
showLanguage
|
showLanguage
|
||||||
buttonTitle={this.buttonTitle}
|
buttonTitle={this.buttonTitle}
|
||||||
finished={this.props.finished}
|
|
||||||
replyType={typeof this.props.node !== "number"}
|
replyType={typeof this.props.node !== "number"}
|
||||||
focus={this.props.focus}
|
focus={this.props.focus}
|
||||||
disabled={this.props.disabled}
|
disabled={this.props.disabled}
|
||||||
|
@ -83,33 +89,38 @@ export class CommentForm extends Component<CommentFormProps, any> {
|
||||||
: capitalizeFirstLetter(I18NextService.i18n.t("reply"));
|
: capitalizeFirstLetter(I18NextService.i18n.t("reply"));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleCommentSubmit(content: string, language_id?: number) {
|
async handleCommentSubmit(
|
||||||
|
content: string,
|
||||||
|
language_id?: number,
|
||||||
|
): Promise<boolean> {
|
||||||
const { node, onUpsertComment, edit } = this.props;
|
const { node, onUpsertComment, edit } = this.props;
|
||||||
|
let response: RequestState<CommentResponse>;
|
||||||
|
|
||||||
if (typeof node === "number") {
|
if (typeof node === "number") {
|
||||||
const post_id = node;
|
const post_id = node;
|
||||||
onUpsertComment({
|
response = await onUpsertComment({
|
||||||
content,
|
content,
|
||||||
post_id,
|
post_id,
|
||||||
language_id,
|
language_id,
|
||||||
});
|
});
|
||||||
|
} else if (edit) {
|
||||||
|
const comment_id = node.comment_view.comment.id;
|
||||||
|
response = await onUpsertComment({
|
||||||
|
content,
|
||||||
|
comment_id,
|
||||||
|
language_id,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
if (edit) {
|
const post_id = node.comment_view.post.id;
|
||||||
const comment_id = node.comment_view.comment.id;
|
const parent_id = node.comment_view.comment.id;
|
||||||
onUpsertComment({
|
response = await onUpsertComment({
|
||||||
content,
|
content,
|
||||||
comment_id,
|
parent_id,
|
||||||
language_id,
|
post_id,
|
||||||
});
|
language_id,
|
||||||
} else {
|
});
|
||||||
const post_id = node.comment_view.post.id;
|
|
||||||
const parent_id = node.comment_view.comment.id;
|
|
||||||
this.props.onUpsertComment({
|
|
||||||
content,
|
|
||||||
parent_id,
|
|
||||||
post_id,
|
|
||||||
language_id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return response.state !== "failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { colorList, getCommentParentId } from "@utils/app";
|
||||||
import { futureDaysToUnixTime, numToSI } from "@utils/helpers";
|
import { futureDaysToUnixTime, numToSI } from "@utils/helpers";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { isBefore, parseISO, subMinutes } from "date-fns";
|
import { isBefore, parseISO, subMinutes } from "date-fns";
|
||||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import { Link } from "inferno-router";
|
import { Link } from "inferno-router";
|
||||||
import {
|
import {
|
||||||
AddAdmin,
|
AddAdmin,
|
||||||
|
@ -33,7 +33,6 @@ import {
|
||||||
SaveComment,
|
SaveComment,
|
||||||
TransferCommunity,
|
TransferCommunity,
|
||||||
} from "lemmy-js-client";
|
} from "lemmy-js-client";
|
||||||
import deepEqual from "lodash.isequal";
|
|
||||||
import { commentTreeMaxDepth } from "../../config";
|
import { commentTreeMaxDepth } from "../../config";
|
||||||
import {
|
import {
|
||||||
CommentNodeI,
|
CommentNodeI,
|
||||||
|
@ -87,7 +86,6 @@ interface CommentNodeProps {
|
||||||
allLanguages: Language[];
|
allLanguages: Language[];
|
||||||
siteLanguages: number[];
|
siteLanguages: number[];
|
||||||
hideImages?: boolean;
|
hideImages?: boolean;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
onSaveComment(form: SaveComment): Promise<void>;
|
onSaveComment(form: SaveComment): Promise<void>;
|
||||||
onCommentReplyRead(form: MarkCommentReplyAsRead): void;
|
onCommentReplyRead(form: MarkCommentReplyAsRead): void;
|
||||||
onPersonMentionRead(form: MarkPersonMentionAsRead): void;
|
onPersonMentionRead(form: MarkPersonMentionAsRead): void;
|
||||||
|
@ -139,6 +137,8 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.handleReplyCancel = this.handleReplyCancel.bind(this);
|
this.handleReplyCancel = this.handleReplyCancel.bind(this);
|
||||||
|
this.handleCreateComment = this.handleCreateComment.bind(this);
|
||||||
|
this.handleEditComment = this.handleEditComment.bind(this);
|
||||||
this.handleReportComment = this.handleReportComment.bind(this);
|
this.handleReportComment = this.handleReportComment.bind(this);
|
||||||
this.handleRemoveComment = this.handleRemoveComment.bind(this);
|
this.handleRemoveComment = this.handleRemoveComment.bind(this);
|
||||||
this.handleReplyClick = this.handleReplyClick.bind(this);
|
this.handleReplyClick = this.handleReplyClick.bind(this);
|
||||||
|
@ -164,22 +164,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
return this.commentView.comment.id;
|
return this.commentView.comment.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(
|
|
||||||
nextProps: Readonly<{ children?: InfernoNode } & CommentNodeProps>,
|
|
||||||
): void {
|
|
||||||
if (!deepEqual(this.props, nextProps)) {
|
|
||||||
this.setState({
|
|
||||||
showEdit: false,
|
|
||||||
showAdvanced: false,
|
|
||||||
createOrEditCommentLoading: false,
|
|
||||||
upvoteLoading: false,
|
|
||||||
downvoteLoading: false,
|
|
||||||
readLoading: false,
|
|
||||||
fetchChildrenLoading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const node = this.props.node;
|
const node = this.props.node;
|
||||||
const cv = this.commentView;
|
const cv = this.commentView;
|
||||||
|
@ -283,12 +267,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
edit
|
edit
|
||||||
onReplyCancel={this.handleReplyCancel}
|
onReplyCancel={this.handleReplyCancel}
|
||||||
disabled={this.props.locked}
|
disabled={this.props.locked}
|
||||||
finished={this.props.finished.get(id)}
|
|
||||||
focus
|
focus
|
||||||
allLanguages={this.props.allLanguages}
|
allLanguages={this.props.allLanguages}
|
||||||
siteLanguages={this.props.siteLanguages}
|
siteLanguages={this.props.siteLanguages}
|
||||||
containerClass="comment-comment-container"
|
containerClass="comment-comment-container"
|
||||||
onUpsertComment={this.props.onEditComment}
|
onUpsertComment={this.handleEditComment}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!this.state.showEdit && !this.state.collapsed && (
|
{!this.state.showEdit && !this.state.collapsed && (
|
||||||
|
@ -425,12 +408,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
node={node}
|
node={node}
|
||||||
onReplyCancel={this.handleReplyCancel}
|
onReplyCancel={this.handleReplyCancel}
|
||||||
disabled={this.props.locked}
|
disabled={this.props.locked}
|
||||||
finished={this.props.finished.get(id)}
|
|
||||||
focus
|
focus
|
||||||
allLanguages={this.props.allLanguages}
|
allLanguages={this.props.allLanguages}
|
||||||
siteLanguages={this.props.siteLanguages}
|
siteLanguages={this.props.siteLanguages}
|
||||||
containerClass="comment-comment-container"
|
containerClass="comment-comment-container"
|
||||||
onUpsertComment={this.props.onCreateComment}
|
onUpsertComment={this.handleCreateComment}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!this.state.collapsed && node.children.length > 0 && (
|
{!this.state.collapsed && node.children.length > 0 && (
|
||||||
|
@ -447,7 +429,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
hideImages={this.props.hideImages}
|
hideImages={this.props.hideImages}
|
||||||
isChild={!this.props.isTopLevel}
|
isChild={!this.props.isTopLevel}
|
||||||
depth={this.props.node.depth + 1}
|
depth={this.props.node.depth + 1}
|
||||||
finished={this.props.finished}
|
|
||||||
onCommentReplyRead={this.props.onCommentReplyRead}
|
onCommentReplyRead={this.props.onCommentReplyRead}
|
||||||
onPersonMentionRead={this.props.onPersonMentionRead}
|
onPersonMentionRead={this.props.onPersonMentionRead}
|
||||||
onCreateComment={this.props.onCreateComment}
|
onCreateComment={this.props.onCreateComment}
|
||||||
|
@ -559,6 +540,26 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
|
||||||
this.setState({ showReply: false, showEdit: false });
|
this.setState({ showReply: false, showEdit: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleCreateComment(
|
||||||
|
form: CreateComment,
|
||||||
|
): Promise<RequestState<CommentResponse>> {
|
||||||
|
const res = await this.props.onCreateComment(form);
|
||||||
|
if (res.state !== "failed") {
|
||||||
|
this.setState({ showReply: false, showEdit: false });
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleEditComment(
|
||||||
|
form: EditComment,
|
||||||
|
): Promise<RequestState<CommentResponse>> {
|
||||||
|
const res = await this.props.onEditComment(form);
|
||||||
|
if (res.state !== "failed") {
|
||||||
|
this.setState({ showReply: false, showEdit: false });
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
isPersonMentionType(item: CommentNodeView): item is PersonMentionView {
|
isPersonMentionType(item: CommentNodeView): item is PersonMentionView {
|
||||||
return item.person_mention?.id !== undefined;
|
return item.person_mention?.id !== undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import {
|
||||||
BanFromCommunity,
|
BanFromCommunity,
|
||||||
BanPerson,
|
BanPerson,
|
||||||
BlockPerson,
|
BlockPerson,
|
||||||
CommentId,
|
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommunityModeratorView,
|
CommunityModeratorView,
|
||||||
CreateComment,
|
CreateComment,
|
||||||
|
@ -52,7 +51,6 @@ interface CommentNodesProps {
|
||||||
hideImages?: boolean;
|
hideImages?: boolean;
|
||||||
isChild?: boolean;
|
isChild?: boolean;
|
||||||
depth?: number;
|
depth?: number;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
onSaveComment(form: SaveComment): Promise<void>;
|
onSaveComment(form: SaveComment): Promise<void>;
|
||||||
onCommentReplyRead(form: MarkCommentReplyAsRead): void;
|
onCommentReplyRead(form: MarkCommentReplyAsRead): void;
|
||||||
onPersonMentionRead(form: MarkPersonMentionAsRead): void;
|
onPersonMentionRead(form: MarkPersonMentionAsRead): void;
|
||||||
|
@ -124,7 +122,6 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
|
||||||
hideImages={this.props.hideImages}
|
hideImages={this.props.hideImages}
|
||||||
onCommentReplyRead={this.props.onCommentReplyRead}
|
onCommentReplyRead={this.props.onCommentReplyRead}
|
||||||
onPersonMentionRead={this.props.onPersonMentionRead}
|
onPersonMentionRead={this.props.onPersonMentionRead}
|
||||||
finished={this.props.finished}
|
|
||||||
onCreateComment={this.props.onCreateComment}
|
onCreateComment={this.props.onCreateComment}
|
||||||
onEditComment={this.props.onEditComment}
|
onEditComment={this.props.onEditComment}
|
||||||
onCommentVote={this.props.onCommentVote}
|
onCommentVote={this.props.onCommentVote}
|
||||||
|
|
|
@ -90,7 +90,6 @@ export class CommentReport extends Component<
|
||||||
siteLanguages={[]}
|
siteLanguages={[]}
|
||||||
hideImages
|
hideImages
|
||||||
// All of these are unused, since its viewonly
|
// All of these are unused, since its viewonly
|
||||||
finished={new Map()}
|
|
||||||
onSaveComment={async () => {}}
|
onSaveComment={async () => {}}
|
||||||
onBlockPerson={async () => {}}
|
onBlockPerson={async () => {}}
|
||||||
onDeleteComment={async () => {}}
|
onDeleteComment={async () => {}}
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { numToSI, randomStr } from "@utils/helpers";
|
||||||
import autosize from "autosize";
|
import autosize from "autosize";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { NoOptionI18nKeys } from "i18next";
|
import { NoOptionI18nKeys } from "i18next";
|
||||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import { Prompt } from "inferno-router";
|
import { Prompt } from "inferno-router";
|
||||||
import { Language } from "lemmy-js-client";
|
import { Language } from "lemmy-js-client";
|
||||||
import {
|
import {
|
||||||
|
@ -41,7 +41,6 @@ interface MarkdownTextAreaProps {
|
||||||
replyType?: boolean;
|
replyType?: boolean;
|
||||||
focus?: boolean;
|
focus?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
finished?: boolean;
|
|
||||||
/**
|
/**
|
||||||
* Whether to show the language selector
|
* Whether to show the language selector
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +48,7 @@ interface MarkdownTextAreaProps {
|
||||||
hideNavigationWarnings?: boolean;
|
hideNavigationWarnings?: boolean;
|
||||||
onContentChange?(val: string): void;
|
onContentChange?(val: string): void;
|
||||||
onReplyCancel?(): void;
|
onReplyCancel?(): void;
|
||||||
onSubmit?(content: string, languageId?: number): void;
|
onSubmit?(content: string, languageId?: number): Promise<boolean>;
|
||||||
allLanguages: Language[]; // TODO should probably be nullable
|
allLanguages: Language[]; // TODO should probably be nullable
|
||||||
siteLanguages: number[]; // TODO same
|
siteLanguages: number[]; // TODO same
|
||||||
}
|
}
|
||||||
|
@ -115,27 +114,6 @@ export class MarkdownTextArea extends Component<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(
|
|
||||||
nextProps: MarkdownTextAreaProps & { children?: InfernoNode },
|
|
||||||
) {
|
|
||||||
if (nextProps.finished) {
|
|
||||||
this.setState({
|
|
||||||
previewMode: false,
|
|
||||||
imageUploadStatus: undefined,
|
|
||||||
loading: false,
|
|
||||||
content: undefined,
|
|
||||||
});
|
|
||||||
if (this.props.replyType) {
|
|
||||||
this.props.onReplyCancel?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
const textarea: any = document.getElementById(this.id);
|
|
||||||
const form: any = document.getElementById(this.formId);
|
|
||||||
form.reset();
|
|
||||||
setTimeout(() => autosize.update(textarea), 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const languageId = this.state.languageId;
|
const languageId = this.state.languageId;
|
||||||
|
|
||||||
|
@ -149,8 +127,8 @@ export class MarkdownTextArea extends Component<
|
||||||
message={I18NextService.i18n.t("block_leaving")}
|
message={I18NextService.i18n.t("block_leaving")}
|
||||||
when={
|
when={
|
||||||
!this.props.hideNavigationWarnings &&
|
!this.props.hideNavigationWarnings &&
|
||||||
!!this.state.content &&
|
((!!this.state.content && !this.state.submitted) ||
|
||||||
!this.state.submitted
|
this.state.loading)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="mb-3 row">
|
<div className="mb-3 row">
|
||||||
|
@ -575,11 +553,15 @@ export class MarkdownTextArea extends Component<
|
||||||
this.setState({ languageId: val[0] });
|
this.setState({ languageId: val[0] });
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(i: MarkdownTextArea, event: any) {
|
async handleSubmit(i: MarkdownTextArea, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (i.state.content) {
|
if (i.state.content) {
|
||||||
i.setState({ loading: true, submitted: true });
|
i.setState({ loading: true, submitted: true });
|
||||||
i.props.onSubmit?.(i.state.content, i.state.languageId);
|
const success = await i.props.onSubmit?.(
|
||||||
|
i.state.content,
|
||||||
|
i.state.languageId,
|
||||||
|
);
|
||||||
|
i.setState({ loading: false, submitted: success ?? true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
editWith,
|
editWith,
|
||||||
enableDownvotes,
|
enableDownvotes,
|
||||||
enableNsfw,
|
enableNsfw,
|
||||||
getCommentParentId,
|
|
||||||
getDataTypeString,
|
getDataTypeString,
|
||||||
postToCommentSortType,
|
postToCommentSortType,
|
||||||
setIsoData,
|
setIsoData,
|
||||||
|
@ -42,7 +41,6 @@ import {
|
||||||
BanPersonResponse,
|
BanPersonResponse,
|
||||||
BlockCommunity,
|
BlockCommunity,
|
||||||
BlockPerson,
|
BlockPerson,
|
||||||
CommentId,
|
|
||||||
CommentReplyResponse,
|
CommentReplyResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommunityResponse,
|
CommunityResponse,
|
||||||
|
@ -136,7 +134,6 @@ interface State {
|
||||||
commentsRes: RequestState<GetCommentsResponse>;
|
commentsRes: RequestState<GetCommentsResponse>;
|
||||||
siteRes: GetSiteResponse;
|
siteRes: GetSiteResponse;
|
||||||
showSidebarMobile: boolean;
|
showSidebarMobile: boolean;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
isIsomorphic: boolean;
|
isIsomorphic: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +198,6 @@ export class Community extends Component<CommunityRouteProps, State> {
|
||||||
commentsRes: EMPTY_REQUEST,
|
commentsRes: EMPTY_REQUEST,
|
||||||
siteRes: this.isoData.site_res,
|
siteRes: this.isoData.site_res,
|
||||||
showSidebarMobile: false,
|
showSidebarMobile: false,
|
||||||
finished: new Map(),
|
|
||||||
isIsomorphic: false,
|
isIsomorphic: false,
|
||||||
};
|
};
|
||||||
private readonly mainContentRef: RefObject<HTMLElement>;
|
private readonly mainContentRef: RefObject<HTMLElement>;
|
||||||
|
@ -528,7 +524,6 @@ export class Community extends Component<CommunityRouteProps, State> {
|
||||||
<CommentNodes
|
<CommentNodes
|
||||||
nodes={commentsToFlatNodes(this.state.commentsRes.data.comments)}
|
nodes={commentsToFlatNodes(this.state.commentsRes.data.comments)}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
finished={this.state.finished}
|
|
||||||
isTopLevel
|
isTopLevel
|
||||||
showContext
|
showContext
|
||||||
enableDownvotes={enableDownvotes(siteRes)}
|
enableDownvotes={enableDownvotes(siteRes)}
|
||||||
|
@ -820,6 +815,9 @@ export class Community extends Component<CommunityRouteProps, State> {
|
||||||
const createCommentRes = await HttpService.client.createComment(form);
|
const createCommentRes = await HttpService.client.createComment(form);
|
||||||
this.createAndUpdateComments(createCommentRes);
|
this.createAndUpdateComments(createCommentRes);
|
||||||
|
|
||||||
|
if (createCommentRes.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(createCommentRes.err.message), "danger");
|
||||||
|
}
|
||||||
return createCommentRes;
|
return createCommentRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,6 +825,9 @@ export class Community extends Component<CommunityRouteProps, State> {
|
||||||
const editCommentRes = await HttpService.client.editComment(form);
|
const editCommentRes = await HttpService.client.editComment(form);
|
||||||
this.findAndUpdateCommentEdit(editCommentRes);
|
this.findAndUpdateCommentEdit(editCommentRes);
|
||||||
|
|
||||||
|
if (editCommentRes.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(editCommentRes.err.message), "danger");
|
||||||
|
}
|
||||||
return editCommentRes;
|
return editCommentRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,7 +1039,6 @@ export class Community extends Component<CommunityRouteProps, State> {
|
||||||
res.data.comment_view,
|
res.data.comment_view,
|
||||||
s.commentsRes.data.comments,
|
s.commentsRes.data.comments,
|
||||||
);
|
);
|
||||||
s.finished.set(res.data.comment_view.comment.id, true);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
@ -1060,12 +1060,6 @@ export class Community extends Component<CommunityRouteProps, State> {
|
||||||
this.setState(s => {
|
this.setState(s => {
|
||||||
if (s.commentsRes.state === "success" && res.state === "success") {
|
if (s.commentsRes.state === "success" && res.state === "success") {
|
||||||
s.commentsRes.data.comments.unshift(res.data.comment_view);
|
s.commentsRes.data.comments.unshift(res.data.comment_view);
|
||||||
|
|
||||||
// Set finished for the parent
|
|
||||||
s.finished.set(
|
|
||||||
getCommentParentId(res.data.comment_view.comment) ?? 0,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
editWith,
|
editWith,
|
||||||
enableDownvotes,
|
enableDownvotes,
|
||||||
enableNsfw,
|
enableNsfw,
|
||||||
getCommentParentId,
|
|
||||||
getDataTypeString,
|
getDataTypeString,
|
||||||
myAuth,
|
myAuth,
|
||||||
postToCommentSortType,
|
postToCommentSortType,
|
||||||
|
@ -37,7 +36,6 @@ import {
|
||||||
BanPerson,
|
BanPerson,
|
||||||
BanPersonResponse,
|
BanPersonResponse,
|
||||||
BlockPerson,
|
BlockPerson,
|
||||||
CommentId,
|
|
||||||
CommentReplyResponse,
|
CommentReplyResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CreateComment,
|
CreateComment,
|
||||||
|
@ -125,7 +123,6 @@ interface HomeState {
|
||||||
subscribedCollapsed: boolean;
|
subscribedCollapsed: boolean;
|
||||||
tagline?: string;
|
tagline?: string;
|
||||||
siteRes: GetSiteResponse;
|
siteRes: GetSiteResponse;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
isIsomorphic: boolean;
|
isIsomorphic: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +271,6 @@ export class Home extends Component<HomeRouteProps, HomeState> {
|
||||||
showTrendingMobile: false,
|
showTrendingMobile: false,
|
||||||
showSidebarMobile: false,
|
showSidebarMobile: false,
|
||||||
subscribedCollapsed: false,
|
subscribedCollapsed: false,
|
||||||
finished: new Map(),
|
|
||||||
isIsomorphic: false,
|
isIsomorphic: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -770,7 +766,6 @@ export class Home extends Component<HomeRouteProps, HomeState> {
|
||||||
<CommentNodes
|
<CommentNodes
|
||||||
nodes={commentsToFlatNodes(comments)}
|
nodes={commentsToFlatNodes(comments)}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
finished={this.state.finished}
|
|
||||||
isTopLevel
|
isTopLevel
|
||||||
showCommunity
|
showCommunity
|
||||||
showContext
|
showContext
|
||||||
|
@ -973,6 +968,9 @@ export class Home extends Component<HomeRouteProps, HomeState> {
|
||||||
const createCommentRes = await HttpService.client.createComment(form);
|
const createCommentRes = await HttpService.client.createComment(form);
|
||||||
this.createAndUpdateComments(createCommentRes);
|
this.createAndUpdateComments(createCommentRes);
|
||||||
|
|
||||||
|
if (createCommentRes.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(createCommentRes.err.message), "danger");
|
||||||
|
}
|
||||||
return createCommentRes;
|
return createCommentRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -980,6 +978,9 @@ export class Home extends Component<HomeRouteProps, HomeState> {
|
||||||
const editCommentRes = await HttpService.client.editComment(form);
|
const editCommentRes = await HttpService.client.editComment(form);
|
||||||
this.findAndUpdateCommentEdit(editCommentRes);
|
this.findAndUpdateCommentEdit(editCommentRes);
|
||||||
|
|
||||||
|
if (editCommentRes.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(editCommentRes.err.message), "danger");
|
||||||
|
}
|
||||||
return editCommentRes;
|
return editCommentRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1168,7 +1169,6 @@ export class Home extends Component<HomeRouteProps, HomeState> {
|
||||||
res.data.comment_view,
|
res.data.comment_view,
|
||||||
s.commentsRes.data.comments,
|
s.commentsRes.data.comments,
|
||||||
);
|
);
|
||||||
s.finished.set(res.data.comment_view.comment.id, true);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
@ -1190,12 +1190,6 @@ export class Home extends Component<HomeRouteProps, HomeState> {
|
||||||
this.setState(s => {
|
this.setState(s => {
|
||||||
if (s.commentsRes.state === "success" && res.state === "success") {
|
if (s.commentsRes.state === "success" && res.state === "success") {
|
||||||
s.commentsRes.data.comments.unshift(res.data.comment_view);
|
s.commentsRes.data.comments.unshift(res.data.comment_view);
|
||||||
|
|
||||||
// Set finished for the parent
|
|
||||||
s.finished.set(
|
|
||||||
getCommentParentId(res.data.comment_view.comment) ?? 0,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
editPrivateMessage,
|
editPrivateMessage,
|
||||||
editWith,
|
editWith,
|
||||||
enableDownvotes,
|
enableDownvotes,
|
||||||
getCommentParentId,
|
|
||||||
myAuth,
|
myAuth,
|
||||||
setIsoData,
|
setIsoData,
|
||||||
updatePersonBlock,
|
updatePersonBlock,
|
||||||
|
@ -28,7 +27,6 @@ import {
|
||||||
BanPerson,
|
BanPerson,
|
||||||
BanPersonResponse,
|
BanPersonResponse,
|
||||||
BlockPerson,
|
BlockPerson,
|
||||||
CommentId,
|
|
||||||
CommentReplyResponse,
|
CommentReplyResponse,
|
||||||
CommentReplyView,
|
CommentReplyView,
|
||||||
CommentReportResponse,
|
CommentReportResponse,
|
||||||
|
@ -132,7 +130,6 @@ interface InboxState {
|
||||||
sort: CommentSortType;
|
sort: CommentSortType;
|
||||||
page: number;
|
page: number;
|
||||||
siteRes: GetSiteResponse;
|
siteRes: GetSiteResponse;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
isIsomorphic: boolean;
|
isIsomorphic: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +154,6 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
mentionsRes: EMPTY_REQUEST,
|
mentionsRes: EMPTY_REQUEST,
|
||||||
messagesRes: EMPTY_REQUEST,
|
messagesRes: EMPTY_REQUEST,
|
||||||
markAllAsReadRes: EMPTY_REQUEST,
|
markAllAsReadRes: EMPTY_REQUEST,
|
||||||
finished: new Map(),
|
|
||||||
isIsomorphic: false,
|
isIsomorphic: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -512,7 +508,6 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
{ comment_view: i.view as CommentView, children: [], depth: 0 },
|
{ comment_view: i.view as CommentView, children: [], depth: 0 },
|
||||||
]}
|
]}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
finished={this.state.finished}
|
|
||||||
markable
|
markable
|
||||||
showCommunity
|
showCommunity
|
||||||
showContext
|
showContext
|
||||||
|
@ -551,7 +546,6 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
depth: 0,
|
depth: 0,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
finished={this.state.finished}
|
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
markable
|
markable
|
||||||
showCommunity
|
showCommunity
|
||||||
|
@ -623,7 +617,6 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
<CommentNodes
|
<CommentNodes
|
||||||
nodes={commentsToFlatNodes(replies)}
|
nodes={commentsToFlatNodes(replies)}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
finished={this.state.finished}
|
|
||||||
markable
|
markable
|
||||||
showCommunity
|
showCommunity
|
||||||
showContext
|
showContext
|
||||||
|
@ -670,7 +663,6 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
key={umv.person_mention.id}
|
key={umv.person_mention.id}
|
||||||
nodes={[{ comment_view: umv, children: [], depth: 0 }]}
|
nodes={[{ comment_view: umv, children: [], depth: 0 }]}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
finished={this.state.finished}
|
|
||||||
markable
|
markable
|
||||||
showCommunity
|
showCommunity
|
||||||
showContext
|
showContext
|
||||||
|
@ -996,9 +988,13 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
this.findAndUpdateMessage(res);
|
this.findAndUpdateMessage(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleEditMessage(form: EditPrivateMessage) {
|
async handleEditMessage(form: EditPrivateMessage): Promise<boolean> {
|
||||||
const res = await HttpService.client.editPrivateMessage(form);
|
const res = await HttpService.client.editPrivateMessage(form);
|
||||||
this.findAndUpdateMessage(res);
|
this.findAndUpdateMessage(res);
|
||||||
|
if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
}
|
||||||
|
return res.state !== "failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleMarkMessageAsRead(form: MarkPrivateMessageAsRead) {
|
async handleMarkMessageAsRead(form: MarkPrivateMessageAsRead) {
|
||||||
|
@ -1015,7 +1011,7 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
this.reportToast(res);
|
this.reportToast(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleCreateMessage(form: CreatePrivateMessage) {
|
async handleCreateMessage(form: CreatePrivateMessage): Promise<boolean> {
|
||||||
const res = await HttpService.client.createPrivateMessage(form);
|
const res = await HttpService.client.createPrivateMessage(form);
|
||||||
this.setState(s => {
|
this.setState(s => {
|
||||||
if (s.messagesRes.state === "success" && res.state === "success") {
|
if (s.messagesRes.state === "success" && res.state === "success") {
|
||||||
|
@ -1026,6 +1022,10 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
}
|
||||||
|
return res.state !== "failed";
|
||||||
}
|
}
|
||||||
|
|
||||||
findAndUpdateMessage(res: RequestState<PrivateMessageResponse>) {
|
findAndUpdateMessage(res: RequestState<PrivateMessageResponse>) {
|
||||||
|
@ -1094,6 +1094,8 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
) {
|
) {
|
||||||
if (res.state === "success") {
|
if (res.state === "success") {
|
||||||
toast(I18NextService.i18n.t("report_created"));
|
toast(I18NextService.i18n.t("report_created"));
|
||||||
|
} else if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1113,11 +1115,6 @@ export class Inbox extends Component<InboxRouteProps, InboxState> {
|
||||||
s.mentionsRes.data.mentions,
|
s.mentionsRes.data.mentions,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Set finished for the parent
|
|
||||||
s.finished.set(
|
|
||||||
getCommentParentId(res.data.comment_view.comment) ?? 0,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import {
|
||||||
BanFromCommunity,
|
BanFromCommunity,
|
||||||
BanPerson,
|
BanPerson,
|
||||||
BlockPerson,
|
BlockPerson,
|
||||||
CommentId,
|
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
CommentView,
|
CommentView,
|
||||||
CreateComment,
|
CreateComment,
|
||||||
|
@ -49,7 +48,6 @@ import { RequestState } from "../../services/HttpService";
|
||||||
|
|
||||||
interface PersonDetailsProps {
|
interface PersonDetailsProps {
|
||||||
personRes: GetPersonDetailsResponse;
|
personRes: GetPersonDetailsResponse;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
admins: PersonView[];
|
admins: PersonView[];
|
||||||
allLanguages: Language[];
|
allLanguages: Language[];
|
||||||
siteLanguages: number[];
|
siteLanguages: number[];
|
||||||
|
@ -153,7 +151,6 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
|
||||||
key={i.id}
|
key={i.id}
|
||||||
nodes={[{ comment_view: c, children: [], depth: 0 }]}
|
nodes={[{ comment_view: c, children: [], depth: 0 }]}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
finished={this.props.finished}
|
|
||||||
admins={this.props.admins}
|
admins={this.props.admins}
|
||||||
noBorder
|
noBorder
|
||||||
showCommunity
|
showCommunity
|
||||||
|
@ -266,7 +263,6 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
|
||||||
nodes={commentsToFlatNodes(this.props.personRes.comments)}
|
nodes={commentsToFlatNodes(this.props.personRes.comments)}
|
||||||
viewType={CommentViewType.Flat}
|
viewType={CommentViewType.Flat}
|
||||||
admins={this.props.admins}
|
admins={this.props.admins}
|
||||||
finished={this.props.finished}
|
|
||||||
isTopLevel
|
isTopLevel
|
||||||
showCommunity
|
showCommunity
|
||||||
showContext
|
showContext
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
editWith,
|
editWith,
|
||||||
enableDownvotes,
|
enableDownvotes,
|
||||||
enableNsfw,
|
enableNsfw,
|
||||||
getCommentParentId,
|
|
||||||
setIsoData,
|
setIsoData,
|
||||||
updatePersonBlock,
|
updatePersonBlock,
|
||||||
voteDisplayMode,
|
voteDisplayMode,
|
||||||
|
@ -38,7 +37,6 @@ import {
|
||||||
BanPerson,
|
BanPerson,
|
||||||
BanPersonResponse,
|
BanPersonResponse,
|
||||||
BlockPerson,
|
BlockPerson,
|
||||||
CommentId,
|
|
||||||
CommentReplyResponse,
|
CommentReplyResponse,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
Community,
|
Community,
|
||||||
|
@ -120,7 +118,6 @@ interface ProfileState {
|
||||||
showBanDialog: boolean;
|
showBanDialog: boolean;
|
||||||
removeData: boolean;
|
removeData: boolean;
|
||||||
siteRes: GetSiteResponse;
|
siteRes: GetSiteResponse;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
isIsomorphic: boolean;
|
isIsomorphic: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +203,6 @@ export class Profile extends Component<ProfileRouteProps, ProfileState> {
|
||||||
siteRes: this.isoData.site_res,
|
siteRes: this.isoData.site_res,
|
||||||
showBanDialog: false,
|
showBanDialog: false,
|
||||||
removeData: false,
|
removeData: false,
|
||||||
finished: new Map(),
|
|
||||||
isIsomorphic: false,
|
isIsomorphic: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -491,7 +487,6 @@ export class Profile extends Component<ProfileRouteProps, ProfileState> {
|
||||||
sort={sort}
|
sort={sort}
|
||||||
page={page}
|
page={page}
|
||||||
limit={fetchLimit}
|
limit={fetchLimit}
|
||||||
finished={this.state.finished}
|
|
||||||
enableDownvotes={enableDownvotes(siteRes)}
|
enableDownvotes={enableDownvotes(siteRes)}
|
||||||
voteDisplayMode={voteDisplayMode(siteRes)}
|
voteDisplayMode={voteDisplayMode(siteRes)}
|
||||||
enableNsfw={enableNsfw(siteRes)}
|
enableNsfw={enableNsfw(siteRes)}
|
||||||
|
@ -1178,7 +1173,6 @@ export class Profile extends Component<ProfileRouteProps, ProfileState> {
|
||||||
res.data.comment_view,
|
res.data.comment_view,
|
||||||
s.personRes.data.comments,
|
s.personRes.data.comments,
|
||||||
);
|
);
|
||||||
s.finished.set(res.data.comment_view.comment.id, true);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
@ -1200,11 +1194,6 @@ export class Profile extends Component<ProfileRouteProps, ProfileState> {
|
||||||
this.setState(s => {
|
this.setState(s => {
|
||||||
if (s.personRes.state === "success" && res.state === "success") {
|
if (s.personRes.state === "success" && res.state === "success") {
|
||||||
s.personRes.data.comments.unshift(res.data.comment_view);
|
s.personRes.data.comments.unshift(res.data.comment_view);
|
||||||
// Set finished for the parent
|
|
||||||
s.finished.set(
|
|
||||||
getCommentParentId(res.data.comment_view.comment) ?? 0,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,7 +27,6 @@ import {
|
||||||
wrapClient,
|
wrapClient,
|
||||||
} from "../../services/HttpService";
|
} from "../../services/HttpService";
|
||||||
import { HtmlTags } from "../common/html-tags";
|
import { HtmlTags } from "../common/html-tags";
|
||||||
import { Spinner } from "../common/icon";
|
|
||||||
import { PostForm } from "./post-form";
|
import { PostForm } from "./post-form";
|
||||||
import { getHttpBaseInternal } from "../../utils/env";
|
import { getHttpBaseInternal } from "../../utils/env";
|
||||||
import { IRoutePropsWithFetch } from "../../routes";
|
import { IRoutePropsWithFetch } from "../../routes";
|
||||||
|
@ -178,39 +177,28 @@ export class CreatePost extends Component<
|
||||||
title={this.documentTitle}
|
title={this.documentTitle}
|
||||||
path={this.context.router.route.match.url}
|
path={this.context.router.route.match.url}
|
||||||
/>
|
/>
|
||||||
{this.state.loading ? (
|
<div className="row">
|
||||||
<h5>
|
<div id="createPostForm" className="col-12 col-lg-6 offset-lg-3 mb-4">
|
||||||
<Spinner large />
|
<h1 className="h4 mb-4">{I18NextService.i18n.t("create_post")}</h1>
|
||||||
</h5>
|
<PostForm
|
||||||
) : (
|
onCreate={this.handlePostCreate}
|
||||||
<div className="row">
|
params={locationState}
|
||||||
<div
|
enableDownvotes={enableDownvotes(siteRes)}
|
||||||
id="createPostForm"
|
voteDisplayMode={voteDisplayMode(siteRes)}
|
||||||
className="col-12 col-lg-6 offset-lg-3 mb-4"
|
enableNsfw={enableNsfw(siteRes)}
|
||||||
>
|
allLanguages={siteRes.all_languages}
|
||||||
<h1 className="h4 mb-4">
|
siteLanguages={siteRes.discussion_languages}
|
||||||
{I18NextService.i18n.t("create_post")}
|
selectedCommunityChoice={selectedCommunityChoice}
|
||||||
</h1>
|
onSelectCommunity={this.handleSelectedCommunityChange}
|
||||||
<PostForm
|
initialCommunities={
|
||||||
onCreate={this.handlePostCreate}
|
this.state.initialCommunitiesRes.state === "success"
|
||||||
params={locationState}
|
? this.state.initialCommunitiesRes.data.communities
|
||||||
enableDownvotes={enableDownvotes(siteRes)}
|
: []
|
||||||
voteDisplayMode={voteDisplayMode(siteRes)}
|
}
|
||||||
enableNsfw={enableNsfw(siteRes)}
|
loading={loading}
|
||||||
allLanguages={siteRes.all_languages}
|
/>
|
||||||
siteLanguages={siteRes.discussion_languages}
|
|
||||||
selectedCommunityChoice={selectedCommunityChoice}
|
|
||||||
onSelectCommunity={this.handleSelectedCommunityChange}
|
|
||||||
initialCommunities={
|
|
||||||
this.state.initialCommunitiesRes.state === "success"
|
|
||||||
? this.state.initialCommunitiesRes.data.communities
|
|
||||||
: []
|
|
||||||
}
|
|
||||||
loading={loading}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -242,11 +230,13 @@ export class CreatePost extends Component<
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async handlePostCreate(form: CreatePostI) {
|
async handlePostCreate(form: CreatePostI, bypassNavWarning: () => void) {
|
||||||
|
this.setState({ loading: true });
|
||||||
const res = await HttpService.client.createPost(form);
|
const res = await HttpService.client.createPost(form);
|
||||||
|
|
||||||
if (res.state === "success") {
|
if (res.state === "success") {
|
||||||
const postId = res.data.post_view.post.id;
|
const postId = res.data.post_view.post.id;
|
||||||
|
bypassNavWarning();
|
||||||
this.props.history.replace(`/post/${postId}`);
|
this.props.history.replace(`/post/${postId}`);
|
||||||
} else if (res.state === "failed") {
|
} else if (res.state === "failed") {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
|
@ -54,8 +54,8 @@ interface PostFormProps {
|
||||||
siteLanguages: number[];
|
siteLanguages: number[];
|
||||||
params?: PostFormParams;
|
params?: PostFormParams;
|
||||||
onCancel?(): void;
|
onCancel?(): void;
|
||||||
onCreate?(form: CreatePost): void;
|
onCreate?(form: CreatePost, bypassNavWarning: () => void): void;
|
||||||
onEdit?(form: EditPost): void;
|
onEdit?(form: EditPost, bypassNavWarning: () => void): void;
|
||||||
enableNsfw?: boolean;
|
enableNsfw?: boolean;
|
||||||
enableDownvotes?: boolean;
|
enableDownvotes?: boolean;
|
||||||
voteDisplayMode: LocalUserVoteDisplayMode;
|
voteDisplayMode: LocalUserVoteDisplayMode;
|
||||||
|
@ -85,6 +85,7 @@ interface PostFormState {
|
||||||
communitySearchOptions: Choice[];
|
communitySearchOptions: Choice[];
|
||||||
previewMode: boolean;
|
previewMode: boolean;
|
||||||
submitted: boolean;
|
submitted: boolean;
|
||||||
|
bypassNavWarning: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePostSubmit(i: PostForm, event: any) {
|
function handlePostSubmit(i: PostForm, event: any) {
|
||||||
|
@ -93,34 +94,46 @@ function handlePostSubmit(i: PostForm, event: any) {
|
||||||
if ((i.state.form.url ?? "") === "") {
|
if ((i.state.form.url ?? "") === "") {
|
||||||
i.setState(s => ((s.form.url = undefined), s));
|
i.setState(s => ((s.form.url = undefined), s));
|
||||||
}
|
}
|
||||||
|
// This forces `props.loading` to become true, then false, to enable the
|
||||||
|
// submit button again.
|
||||||
i.setState({ submitted: true });
|
i.setState({ submitted: true });
|
||||||
|
|
||||||
const pForm = i.state.form;
|
const pForm = i.state.form;
|
||||||
const pv = i.props.post_view;
|
const pv = i.props.post_view;
|
||||||
|
|
||||||
if (pv) {
|
if (pv) {
|
||||||
i.props.onEdit?.({
|
i.props.onEdit?.(
|
||||||
post_id: pv.post.id,
|
{
|
||||||
name: pForm.name,
|
post_id: pv.post.id,
|
||||||
url: pForm.url,
|
name: pForm.name,
|
||||||
body: pForm.body,
|
url: pForm.url,
|
||||||
nsfw: pForm.nsfw,
|
body: pForm.body,
|
||||||
language_id: pForm.language_id,
|
nsfw: pForm.nsfw,
|
||||||
custom_thumbnail: pForm.custom_thumbnail,
|
language_id: pForm.language_id,
|
||||||
alt_text: pForm.alt_text,
|
custom_thumbnail: pForm.custom_thumbnail,
|
||||||
});
|
alt_text: pForm.alt_text,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
i.setState({ bypassNavWarning: true });
|
||||||
|
},
|
||||||
|
);
|
||||||
} else if (pForm.name && pForm.community_id) {
|
} else if (pForm.name && pForm.community_id) {
|
||||||
i.props.onCreate?.({
|
i.props.onCreate?.(
|
||||||
name: pForm.name,
|
{
|
||||||
community_id: pForm.community_id,
|
name: pForm.name,
|
||||||
url: pForm.url,
|
community_id: pForm.community_id,
|
||||||
body: pForm.body,
|
url: pForm.url,
|
||||||
nsfw: pForm.nsfw,
|
body: pForm.body,
|
||||||
language_id: pForm.language_id,
|
nsfw: pForm.nsfw,
|
||||||
honeypot: pForm.honeypot,
|
language_id: pForm.language_id,
|
||||||
custom_thumbnail: pForm.custom_thumbnail,
|
honeypot: pForm.honeypot,
|
||||||
alt_text: pForm.alt_text,
|
custom_thumbnail: pForm.custom_thumbnail,
|
||||||
});
|
alt_text: pForm.alt_text,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
i.setState({ bypassNavWarning: true });
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +260,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
previewMode: false,
|
previewMode: false,
|
||||||
communitySearchOptions: [],
|
communitySearchOptions: [],
|
||||||
submitted: false,
|
submitted: false,
|
||||||
|
bypassNavWarning: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
postTitleRef = createRef<HTMLTextAreaElement>();
|
postTitleRef = createRef<HTMLTextAreaElement>();
|
||||||
|
@ -347,6 +361,9 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
nextProps.initialCommunities?.map(communityToChoice) ?? [],
|
nextProps.initialCommunities?.map(communityToChoice) ?? [],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.props.loading && !nextProps.loading) {
|
||||||
|
this.setState({ submitted: false, bypassNavWarning: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -364,7 +381,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
this.state.form.name ||
|
this.state.form.name ||
|
||||||
this.state.form.url ||
|
this.state.form.url ||
|
||||||
this.state.form.body
|
this.state.form.body
|
||||||
) && !this.state.submitted
|
) && !this.state.bypassNavWarning
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div className="mb-3 row">
|
<div className="mb-3 row">
|
||||||
|
@ -618,7 +635,11 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
|
||||||
<div className="mb-3 row">
|
<div className="mb-3 row">
|
||||||
<div className="col-sm-10">
|
<div className="col-sm-10">
|
||||||
<button
|
<button
|
||||||
disabled={!this.state.form.community_id || this.props.loading}
|
disabled={
|
||||||
|
!this.state.form.community_id ||
|
||||||
|
this.props.loading ||
|
||||||
|
this.state.submitted
|
||||||
|
}
|
||||||
type="submit"
|
type="submit"
|
||||||
className="btn btn-secondary me-2"
|
className="btn btn-secondary me-2"
|
||||||
>
|
>
|
||||||
|
|
|
@ -842,13 +842,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
||||||
|
|
||||||
// The actual editing is done in the receive for post
|
// The actual editing is done in the receive for post
|
||||||
async handleEditPost(form: EditPost) {
|
async handleEditPost(form: EditPost) {
|
||||||
this.setState({ showEdit: false, loading: true });
|
this.setState({ loading: true });
|
||||||
const res = await this.props.onPostEdit(form);
|
const res = await this.props.onPostEdit(form);
|
||||||
|
|
||||||
if (res.state === "success") {
|
if (res.state === "success") {
|
||||||
toast(I18NextService.i18n.t("edited_post"));
|
toast(I18NextService.i18n.t("edited_post"));
|
||||||
|
this.setState({ loading: false, showEdit: false });
|
||||||
} else if (res.state === "failed") {
|
} else if (res.state === "failed") {
|
||||||
toast(I18NextService.i18n.t(res.err.message), "danger");
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
this.setState({ loading: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,8 +120,8 @@ interface PostState {
|
||||||
siteRes: GetSiteResponse;
|
siteRes: GetSiteResponse;
|
||||||
showSidebarMobile: boolean;
|
showSidebarMobile: boolean;
|
||||||
maxCommentsShown: number;
|
maxCommentsShown: number;
|
||||||
finished: Map<CommentId, boolean | undefined>;
|
|
||||||
isIsomorphic: boolean;
|
isIsomorphic: boolean;
|
||||||
|
lastCreatedCommentId?: CommentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultCommentSort: CommentSortType = "Hot";
|
const defaultCommentSort: CommentSortType = "Hot";
|
||||||
|
@ -219,7 +219,6 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
siteRes: this.isoData.site_res,
|
siteRes: this.isoData.site_res,
|
||||||
showSidebarMobile: false,
|
showSidebarMobile: false,
|
||||||
maxCommentsShown: commentsShownInterval,
|
maxCommentsShown: commentsShownInterval,
|
||||||
finished: new Map(),
|
|
||||||
isIsomorphic: false,
|
isIsomorphic: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,6 +235,8 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
this.handleFollow = this.handleFollow.bind(this);
|
this.handleFollow = this.handleFollow.bind(this);
|
||||||
this.handleModRemoveCommunity = this.handleModRemoveCommunity.bind(this);
|
this.handleModRemoveCommunity = this.handleModRemoveCommunity.bind(this);
|
||||||
this.handleCreateComment = this.handleCreateComment.bind(this);
|
this.handleCreateComment = this.handleCreateComment.bind(this);
|
||||||
|
this.handleCreateToplevelComment =
|
||||||
|
this.handleCreateToplevelComment.bind(this);
|
||||||
this.handleEditComment = this.handleEditComment.bind(this);
|
this.handleEditComment = this.handleEditComment.bind(this);
|
||||||
this.handleSaveComment = this.handleSaveComment.bind(this);
|
this.handleSaveComment = this.handleSaveComment.bind(this);
|
||||||
this.handleBlockCommunity = this.handleBlockCommunity.bind(this);
|
this.handleBlockCommunity = this.handleBlockCommunity.bind(this);
|
||||||
|
@ -585,7 +586,8 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
) && (
|
) && (
|
||||||
<CommentForm
|
<CommentForm
|
||||||
key={
|
key={
|
||||||
this.context.router.history.location.key
|
this.context.router.history.location.key +
|
||||||
|
this.state.lastCreatedCommentId
|
||||||
// reset on new location, otherwise <Prompt /> stops working
|
// reset on new location, otherwise <Prompt /> stops working
|
||||||
}
|
}
|
||||||
node={res.post_view.post.id}
|
node={res.post_view.post.id}
|
||||||
|
@ -593,8 +595,7 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
allLanguages={siteRes.all_languages}
|
allLanguages={siteRes.all_languages}
|
||||||
siteLanguages={siteRes.discussion_languages}
|
siteLanguages={siteRes.discussion_languages}
|
||||||
containerClass="post-comment-container"
|
containerClass="post-comment-container"
|
||||||
onUpsertComment={this.handleCreateComment}
|
onUpsertComment={this.handleCreateToplevelComment}
|
||||||
finished={this.state.finished.get(0)}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="d-block d-md-none">
|
<div className="d-block d-md-none">
|
||||||
|
@ -774,7 +775,6 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
enableDownvotes={enableDownvotes(siteRes)}
|
enableDownvotes={enableDownvotes(siteRes)}
|
||||||
voteDisplayMode={voteDisplayMode(siteRes)}
|
voteDisplayMode={voteDisplayMode(siteRes)}
|
||||||
showContext
|
showContext
|
||||||
finished={this.state.finished}
|
|
||||||
allLanguages={siteRes.all_languages}
|
allLanguages={siteRes.all_languages}
|
||||||
siteLanguages={siteRes.discussion_languages}
|
siteLanguages={siteRes.discussion_languages}
|
||||||
onSaveComment={this.handleSaveComment}
|
onSaveComment={this.handleSaveComment}
|
||||||
|
@ -885,7 +885,6 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
admins={siteRes.admins}
|
admins={siteRes.admins}
|
||||||
enableDownvotes={enableDownvotes(siteRes)}
|
enableDownvotes={enableDownvotes(siteRes)}
|
||||||
voteDisplayMode={voteDisplayMode(siteRes)}
|
voteDisplayMode={voteDisplayMode(siteRes)}
|
||||||
finished={this.state.finished}
|
|
||||||
allLanguages={siteRes.all_languages}
|
allLanguages={siteRes.all_languages}
|
||||||
siteLanguages={siteRes.discussion_languages}
|
siteLanguages={siteRes.discussion_languages}
|
||||||
onSaveComment={this.handleSaveComment}
|
onSaveComment={this.handleSaveComment}
|
||||||
|
@ -1063,6 +1062,14 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleCreateToplevelComment(form: CreateComment) {
|
||||||
|
const res = await this.handleCreateComment(form);
|
||||||
|
if (res.state === "success") {
|
||||||
|
this.setState({ lastCreatedCommentId: res.data.comment_view.comment.id });
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
async handleCreateComment(form: CreateComment) {
|
async handleCreateComment(form: CreateComment) {
|
||||||
const createCommentRes = await HttpService.client.createComment(form);
|
const createCommentRes = await HttpService.client.createComment(form);
|
||||||
this.createAndUpdateComments(createCommentRes);
|
this.createAndUpdateComments(createCommentRes);
|
||||||
|
@ -1380,12 +1387,12 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
);
|
);
|
||||||
|
|
||||||
comments.splice(foundCommentParentIndex + 1, 0, newComment);
|
comments.splice(foundCommentParentIndex + 1, 0, newComment);
|
||||||
|
|
||||||
// Set finished for the parent
|
|
||||||
s.finished.set(newCommentParentId ?? 0, true);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findAndUpdateCommentEdit(res: RequestState<CommentResponse>) {
|
findAndUpdateCommentEdit(res: RequestState<CommentResponse>) {
|
||||||
|
@ -1395,13 +1402,14 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
res.data.comment_view,
|
res.data.comment_view,
|
||||||
s.commentsRes.data.comments,
|
s.commentsRes.data.comments,
|
||||||
);
|
);
|
||||||
s.finished.set(res.data.comment_view.comment.id, true);
|
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No need to set finished on a comment vote, save, etc
|
|
||||||
findAndUpdateComment(res: RequestState<CommentResponse>) {
|
findAndUpdateComment(res: RequestState<CommentResponse>) {
|
||||||
this.setState(s => {
|
this.setState(s => {
|
||||||
if (s.commentsRes.state === "success" && res.state === "success") {
|
if (s.commentsRes.state === "success" && res.state === "success") {
|
||||||
|
@ -1412,6 +1420,9 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findAndUpdateCommentReply(res: RequestState<CommentReplyResponse>) {
|
findAndUpdateCommentReply(res: RequestState<CommentReplyResponse>) {
|
||||||
|
@ -1424,6 +1435,9 @@ export class Post extends Component<PostRouteProps, PostState> {
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateModerators(res: RequestState<AddModToCommunityResponse>) {
|
updateModerators(res: RequestState<AddModToCommunityResponse>) {
|
||||||
|
|
|
@ -168,14 +168,22 @@ export class CreatePrivateMessage extends Component<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async handlePrivateMessageCreate(form: CreatePrivateMessageI) {
|
async handlePrivateMessageCreate(
|
||||||
|
form: CreatePrivateMessageI,
|
||||||
|
bypassNavWarning: () => void,
|
||||||
|
): Promise<boolean> {
|
||||||
const res = await HttpService.client.createPrivateMessage(form);
|
const res = await HttpService.client.createPrivateMessage(form);
|
||||||
|
|
||||||
if (res.state === "success") {
|
if (res.state === "success") {
|
||||||
toast(I18NextService.i18n.t("message_sent"));
|
toast(I18NextService.i18n.t("message_sent"));
|
||||||
|
|
||||||
|
bypassNavWarning();
|
||||||
// Navigate to the front
|
// Navigate to the front
|
||||||
this.context.router.history.push("/");
|
this.context.router.history.push("/");
|
||||||
|
} else if (res.state === "failed") {
|
||||||
|
toast(I18NextService.i18n.t(res.err.message), "danger");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return res.state !== "failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { capitalizeFirstLetter } from "@utils/helpers";
|
import { capitalizeFirstLetter } from "@utils/helpers";
|
||||||
import { Component, InfernoNode } from "inferno";
|
import { Component } from "inferno";
|
||||||
import { T } from "inferno-i18next-dess";
|
import { T } from "inferno-i18next-dess";
|
||||||
import { Prompt } from "inferno-router";
|
import { Prompt } from "inferno-router";
|
||||||
import {
|
import {
|
||||||
|
@ -19,8 +19,14 @@ interface PrivateMessageFormProps {
|
||||||
privateMessageView?: PrivateMessageView; // If a pm is given, that means this is an edit
|
privateMessageView?: PrivateMessageView; // If a pm is given, that means this is an edit
|
||||||
replyType?: boolean;
|
replyType?: boolean;
|
||||||
onCancel?(): any;
|
onCancel?(): any;
|
||||||
onCreate?(form: CreatePrivateMessage): void;
|
onCreate?(
|
||||||
onEdit?(form: EditPrivateMessage): void;
|
form: CreatePrivateMessage,
|
||||||
|
bypassNavWarning: () => void,
|
||||||
|
): Promise<boolean>;
|
||||||
|
onEdit?(
|
||||||
|
form: EditPrivateMessage,
|
||||||
|
bypassNavWarning: () => void,
|
||||||
|
): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PrivateMessageFormState {
|
interface PrivateMessageFormState {
|
||||||
|
@ -28,6 +34,7 @@ interface PrivateMessageFormState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
previewMode: boolean;
|
previewMode: boolean;
|
||||||
submitted: boolean;
|
submitted: boolean;
|
||||||
|
bypassNavWarning?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrivateMessageForm extends Component<
|
export class PrivateMessageForm extends Component<
|
||||||
|
@ -51,21 +58,15 @@ export class PrivateMessageForm extends Component<
|
||||||
this.handlePrivateMessageSubmit.bind(this);
|
this.handlePrivateMessageSubmit.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(
|
|
||||||
nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageFormProps>,
|
|
||||||
): void {
|
|
||||||
if (this.props !== nextProps) {
|
|
||||||
this.setState({ loading: false, content: undefined, previewMode: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<form className="private-message-form">
|
<form className="private-message-form">
|
||||||
<Prompt
|
<Prompt
|
||||||
message={I18NextService.i18n.t("block_leaving")}
|
message={I18NextService.i18n.t("block_leaving")}
|
||||||
when={
|
when={
|
||||||
!this.state.loading && !!this.state.content && !this.state.submitted
|
!this.state.bypassNavWarning &&
|
||||||
|
((!!this.state.content && !this.state.submitted) ||
|
||||||
|
this.state.loading)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{!this.props.privateMessageView && (
|
{!this.props.privateMessageView && (
|
||||||
|
@ -140,21 +141,34 @@ export class PrivateMessageForm extends Component<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePrivateMessageSubmit() {
|
async handlePrivateMessageSubmit(): Promise<boolean> {
|
||||||
this.setState({ loading: true, submitted: true });
|
this.setState({ loading: true, submitted: true });
|
||||||
const pm = this.props.privateMessageView;
|
const pm = this.props.privateMessageView;
|
||||||
const content = this.state.content ?? "";
|
const content = this.state.content ?? "";
|
||||||
|
let success: boolean | undefined;
|
||||||
if (pm) {
|
if (pm) {
|
||||||
this.props.onEdit?.({
|
success = await this.props.onEdit?.(
|
||||||
private_message_id: pm.private_message.id,
|
{
|
||||||
content,
|
private_message_id: pm.private_message.id,
|
||||||
});
|
content,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.setState({ bypassNavWarning: true });
|
||||||
|
},
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.props.onCreate?.({
|
success = await this.props.onCreate?.(
|
||||||
content,
|
{
|
||||||
recipient_id: this.props.recipient.id,
|
content,
|
||||||
});
|
recipient_id: this.props.recipient.id,
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
this.setState({ bypassNavWarning: true });
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
this.setState({ loading: false, submitted: success ?? true });
|
||||||
|
return success ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleContentChange(val: string) {
|
handleContentChange(val: string) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, InfernoNode, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
import {
|
import {
|
||||||
CreatePrivateMessage,
|
CreatePrivateMessage,
|
||||||
CreatePrivateMessageReport,
|
CreatePrivateMessageReport,
|
||||||
|
@ -32,8 +32,8 @@ interface PrivateMessageProps {
|
||||||
onDelete(form: DeletePrivateMessage): void;
|
onDelete(form: DeletePrivateMessage): void;
|
||||||
onMarkRead(form: MarkPrivateMessageAsRead): void;
|
onMarkRead(form: MarkPrivateMessageAsRead): void;
|
||||||
onReport(form: CreatePrivateMessageReport): void;
|
onReport(form: CreatePrivateMessageReport): void;
|
||||||
onCreate(form: CreatePrivateMessage): void;
|
onCreate(form: CreatePrivateMessage): Promise<boolean>;
|
||||||
onEdit(form: EditPrivateMessage): void;
|
onEdit(form: EditPrivateMessage): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@tippyMixin
|
@tippyMixin
|
||||||
|
@ -56,6 +56,8 @@ export class PrivateMessage extends Component<
|
||||||
this.handleReplyCancel = this.handleReplyCancel.bind(this);
|
this.handleReplyCancel = this.handleReplyCancel.bind(this);
|
||||||
this.handleReportSubmit = this.handleReportSubmit.bind(this);
|
this.handleReportSubmit = this.handleReportSubmit.bind(this);
|
||||||
this.hideReportDialog = this.hideReportDialog.bind(this);
|
this.hideReportDialog = this.hideReportDialog.bind(this);
|
||||||
|
this.handleCreate = this.handleCreate.bind(this);
|
||||||
|
this.handleEdit = this.handleEdit.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
get mine(): boolean {
|
get mine(): boolean {
|
||||||
|
@ -65,22 +67,6 @@ export class PrivateMessage extends Component<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(
|
|
||||||
nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageProps>,
|
|
||||||
): void {
|
|
||||||
if (this.props !== nextProps) {
|
|
||||||
this.setState({
|
|
||||||
showReply: false,
|
|
||||||
showEdit: false,
|
|
||||||
collapsed: false,
|
|
||||||
viewSource: false,
|
|
||||||
showReportDialog: false,
|
|
||||||
deleteLoading: false,
|
|
||||||
readLoading: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const message_view = this.props.private_message_view;
|
const message_view = this.props.private_message_view;
|
||||||
const otherPerson: Person = this.mine
|
const otherPerson: Person = this.mine
|
||||||
|
@ -126,7 +112,7 @@ export class PrivateMessage extends Component<
|
||||||
<PrivateMessageForm
|
<PrivateMessageForm
|
||||||
recipient={otherPerson}
|
recipient={otherPerson}
|
||||||
privateMessageView={message_view}
|
privateMessageView={message_view}
|
||||||
onEdit={this.props.onEdit}
|
onEdit={this.handleEdit}
|
||||||
onCancel={this.handleReplyCancel}
|
onCancel={this.handleReplyCancel}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -265,7 +251,7 @@ export class PrivateMessage extends Component<
|
||||||
<PrivateMessageForm
|
<PrivateMessageForm
|
||||||
replyType={true}
|
replyType={true}
|
||||||
recipient={otherPerson}
|
recipient={otherPerson}
|
||||||
onCreate={this.props.onCreate}
|
onCreate={this.handleCreate}
|
||||||
onCancel={this.handleReplyCancel}
|
onCancel={this.handleReplyCancel}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -304,7 +290,6 @@ export class PrivateMessage extends Component<
|
||||||
|
|
||||||
handleEditClick(i: PrivateMessage) {
|
handleEditClick(i: PrivateMessage) {
|
||||||
i.setState({ showEdit: true });
|
i.setState({ showEdit: true });
|
||||||
i.setState(i.state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteClick(i: PrivateMessage) {
|
handleDeleteClick(i: PrivateMessage) {
|
||||||
|
@ -319,6 +304,22 @@ export class PrivateMessage extends Component<
|
||||||
this.setState({ showReply: false, showEdit: false });
|
this.setState({ showReply: false, showEdit: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleCreate(form: CreatePrivateMessage): Promise<boolean> {
|
||||||
|
const success = await this.props.onCreate(form);
|
||||||
|
if (success) {
|
||||||
|
this.setState({ showReply: false });
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleEdit(form: EditPrivateMessage): Promise<boolean> {
|
||||||
|
const success = await this.props.onEdit(form);
|
||||||
|
if (success) {
|
||||||
|
this.setState({ showEdit: false });
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
handleMarkRead(i: PrivateMessage) {
|
handleMarkRead(i: PrivateMessage) {
|
||||||
i.setState({ readLoading: true });
|
i.setState({ readLoading: true });
|
||||||
i.props.onMarkRead({
|
i.props.onMarkRead({
|
||||||
|
|
|
@ -824,7 +824,6 @@ export class Search extends Component<SearchRouteProps, SearchState> {
|
||||||
allLanguages={siteRes.all_languages}
|
allLanguages={siteRes.all_languages}
|
||||||
siteLanguages={siteRes.discussion_languages}
|
siteLanguages={siteRes.discussion_languages}
|
||||||
// All of these are unused, since its viewonly
|
// All of these are unused, since its viewonly
|
||||||
finished={new Map()}
|
|
||||||
onSaveComment={async () => {}}
|
onSaveComment={async () => {}}
|
||||||
onBlockPerson={async () => {}}
|
onBlockPerson={async () => {}}
|
||||||
onDeleteComment={async () => {}}
|
onDeleteComment={async () => {}}
|
||||||
|
@ -886,7 +885,6 @@ export class Search extends Component<SearchRouteProps, SearchState> {
|
||||||
allLanguages={siteRes.all_languages}
|
allLanguages={siteRes.all_languages}
|
||||||
siteLanguages={siteRes.discussion_languages}
|
siteLanguages={siteRes.discussion_languages}
|
||||||
// All of these are unused, since its viewonly
|
// All of these are unused, since its viewonly
|
||||||
finished={new Map()}
|
|
||||||
onSaveComment={async () => {}}
|
onSaveComment={async () => {}}
|
||||||
onBlockPerson={async () => {}}
|
onBlockPerson={async () => {}}
|
||||||
onDeleteComment={async () => {}}
|
onDeleteComment={async () => {}}
|
||||||
|
|
Loading…
Reference in a new issue