A few more fixes.

This commit is contained in:
Dessalines 2023-06-03 23:20:41 -04:00
parent e64b71339d
commit f981f103ef
19 changed files with 249 additions and 116 deletions

View file

@ -1,4 +1,4 @@
# lemmy-ui
# Lemmy-UI
The official web app for [Lemmy](https://github.com/LemmyNet/lemmy), written in inferno.
@ -8,14 +8,13 @@ Based off of MrFoxPro's [inferno-isomorphic-template](https://github.com/MrFoxPr
The following environment variables can be used to configure lemmy-ui:
`ENV_VAR` | type | default | description
--- | --- | --- | ---
`LEMMY_UI_HOST` | `string` | `0.0.0.0:1234` | The IP / port that the lemmy-ui isomorphic node server is hosted at.
`LEMMY_UI_LEMMY_INTERNAL_HOST` | `string` | `0.0.0.0:8536` | The internal IP / port that lemmy is hosted at. Often `lemmy:8536` if using docker.
`LEMMY_UI_LEMMY_EXTERNAL_HOST` | `string` | `0.0.0.0:8536` | The external IP / port that lemmy is hosted at. Often `DOMAIN.TLD`.
`LEMMY_UI_LEMMY_WS_HOST` | `string` | `0.0.0.0:8536` | An alternate location for lemmy's websocket address. Not usually necessary.
`LEMMY_UI_HTTPS` | `bool` | `false` | Whether to use https.
`LEMMY_UI_EXTRA_THEMES_FOLDER` | `string` | `./extra_themes` | A location for additional lemmy css themes.
`LEMMY_UI_DEBUG` | `bool` | `false` | Loads the [Eruda](https://github.com/liriliri/eruda) debugging utility.
`LEMMY_UI_DISABLE_CSP` | `bool` | `false` | Disables CSP security headers
`LEMMY_UI_CUSTOM_HTML_HEADER` | `string` | | Injects a custom script into `<head>`.
| `ENV_VAR` | type | default | description |
| ------------------------------ | -------- | ---------------- | ----------------------------------------------------------------------------------- |
| `LEMMY_UI_HOST` | `string` | `0.0.0.0:1234` | The IP / port that the lemmy-ui isomorphic node server is hosted at. |
| `LEMMY_UI_LEMMY_INTERNAL_HOST` | `string` | `0.0.0.0:8536` | The internal IP / port that lemmy is hosted at. Often `lemmy:8536` if using docker. |
| `LEMMY_UI_LEMMY_EXTERNAL_HOST` | `string` | `0.0.0.0:8536` | The external IP / port that lemmy is hosted at. Often `DOMAIN.TLD`. |
| `LEMMY_UI_HTTPS` | `bool` | `false` | Whether to use https. |
| `LEMMY_UI_EXTRA_THEMES_FOLDER` | `string` | `./extra_themes` | A location for additional lemmy css themes. |
| `LEMMY_UI_DEBUG` | `bool` | `false` | Loads the [Eruda](https://github.com/liriliri/eruda) debugging utility. |
| `LEMMY_UI_DISABLE_CSP` | `bool` | `false` | Disables CSP security headers |
| `LEMMY_UI_CUSTOM_HTML_HEADER` | `string` | | Injects a custom script into `<head>`. |

View file

@ -14,6 +14,7 @@ interface CommentFormProps {
* Can either be the parent, or the editable comment. The right side is a postId.
*/
node: CommentNodeI | number;
finished?: boolean;
edit?: boolean;
disabled?: boolean;
focus?: boolean;
@ -24,25 +25,11 @@ interface CommentFormProps {
onEditComment(form: EditComment): void;
}
interface CommentFormState {
buttonTitle: string;
}
export class CommentForm extends Component<CommentFormProps, CommentFormState> {
state: CommentFormState = {
buttonTitle:
typeof this.props.node === "number"
? capitalizeFirstLetter(i18n.t("post"))
: this.props.edit
? capitalizeFirstLetter(i18n.t("save"))
: capitalizeFirstLetter(i18n.t("reply")),
};
export class CommentForm extends Component<CommentFormProps, any> {
constructor(props: any, context: any) {
super(props, context);
this.handleCommentSubmit = this.handleCommentSubmit.bind(this);
this.handleReplyCancel = this.handleReplyCancel.bind(this);
}
render() {
@ -59,12 +46,13 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
<MarkdownTextArea
initialContent={initialContent}
showLanguage
buttonTitle={this.state.buttonTitle}
buttonTitle={this.buttonTitle}
finished={this.props.finished}
replyType={typeof this.props.node !== "number"}
focus={this.props.focus}
disabled={this.props.disabled}
onSubmit={this.handleCommentSubmit}
onReplyCancel={this.handleReplyCancel}
onReplyCancel={this.props.onReplyCancel}
placeholder={i18n.t("comment_here")}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
@ -84,6 +72,14 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
);
}
get buttonTitle(): string {
return typeof this.props.node === "number"
? capitalizeFirstLetter(i18n.t("post"))
: this.props.edit
? capitalizeFirstLetter(i18n.t("save"))
: capitalizeFirstLetter(i18n.t("reply"));
}
handleCommentSubmit(content: string, form_id: string, language_id?: number) {
let node = this.props.node;
@ -100,6 +96,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
if (this.props.edit) {
let comment_id = node.comment_view.comment.id;
this.props.onEditComment({
content,
comment_id,
form_id,
language_id,
@ -119,8 +116,4 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
}
}
}
handleReplyCancel() {
this.props.onReplyCancel?.();
}
}

View file

@ -121,6 +121,7 @@ interface CommentNodeProps {
allLanguages: Language[];
siteLanguages: number[];
hideImages?: boolean;
finished: Map<CommentId, boolean | undefined>;
onSaveComment(form: SaveComment): void;
onCommentReplyRead(form: MarkCommentReplyAsRead): void;
onPersonMentionRead(form: MarkPersonMentionAsRead): void;
@ -197,6 +198,22 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
): void {
if (this.props != nextProps) {
this.setState({
showReply: false,
showEdit: false,
showRemoveDialog: false,
showBanDialog: false,
removeData: false,
banType: BanType.Community,
showPurgeDialog: false,
purgeType: PurgeType.Person,
collapsed: false,
viewSource: false,
showAdvanced: false,
showConfirmTransferSite: false,
showConfirmTransferCommunity: false,
showConfirmAppointAsMod: false,
showConfirmAppointAsAdmin: false,
showReportDialog: false,
createOrEditCommentLoading: false,
upvoteLoading: false,
downvoteLoading: false,
@ -389,6 +406,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
edit
onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked}
finished={this.props.finished.get(
this.props.node.comment_view.comment.id
)}
focus
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
@ -1130,6 +1150,9 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
node={node}
onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked}
finished={this.props.finished.get(
this.props.node.comment_view.comment.id
)}
focus
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
@ -1148,6 +1171,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
hideImages={this.props.hideImages}
finished={this.props.finished}
onCommentReplyRead={this.props.onCommentReplyRead}
onPersonMentionRead={this.props.onPersonMentionRead}
onCreateComment={this.props.onCreateComment}
@ -1457,7 +1481,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
read: !cv.person_mention.read,
auth: myAuthRequired(),
});
} else if (this.isCommentReplyType(cv)) {
} else if (i.isCommentReplyType(cv)) {
i.props.onCommentReplyRead({
comment_reply_id: cv.comment_reply.id,
read: !cv.comment_reply.read,

View file

@ -5,6 +5,7 @@ import {
BanFromCommunity,
BanPerson,
BlockPerson,
CommentId,
CommunityModeratorView,
CreateComment,
CreateCommentLike,
@ -43,6 +44,7 @@ interface CommentNodesProps {
allLanguages: Language[];
siteLanguages: number[];
hideImages?: boolean;
finished: Map<CommentId, boolean | undefined>;
onSaveComment(form: SaveComment): void;
onCommentReplyRead(form: MarkCommentReplyAsRead): void;
onPersonMentionRead(form: MarkPersonMentionAsRead): void;
@ -94,6 +96,7 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
hideImages={this.props.hideImages}
onCommentReplyRead={this.props.onCommentReplyRead}
onPersonMentionRead={this.props.onPersonMentionRead}
finished={this.props.finished}
onCreateComment={this.props.onCreateComment}
onEditComment={this.props.onEditComment}
onCommentVote={this.props.onCommentVote}

View file

@ -1,4 +1,4 @@
import { Component, linkEvent } from "inferno";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
CommentReportView,
@ -32,6 +32,14 @@ export class CommentReport extends Component<
super(props, context);
}
componentWillReceiveProps(
nextProps: Readonly<{ children?: InfernoNode } & CommentReportProps>
): void {
if (this.props != nextProps) {
this.setState({ loading: false });
}
}
render() {
let r = this.props.report;
let comment = r.comment;
@ -73,6 +81,7 @@ export class CommentReport extends Component<
siteLanguages={[]}
hideImages
// All of these are unused, since its viewonly
finished={new Map()}
onSaveComment={() => {}}
onBlockPerson={() => {}}
onDeleteComment={() => {}}

View file

@ -36,6 +36,7 @@ interface MarkdownTextAreaProps {
replyType?: boolean;
focus?: boolean;
disabled?: boolean;
finished?: boolean;
showLanguage?: boolean;
hideNavigationWarnings?: boolean;
onContentChange?(val: string): void;
@ -113,12 +114,7 @@ export class MarkdownTextArea extends Component<
}
componentWillReceiveProps(nextProps: MarkdownTextAreaProps) {
if (
nextProps != this.props &&
// Don't trigger this on an initial content change (IE the form field version)
// This should only trigger in an
this.props.initialContent == nextProps.initialContent
) {
if (nextProps.finished) {
this.setState({
previewMode: false,
imageUploadStatus: undefined,

View file

@ -10,6 +10,7 @@ import {
BanPersonResponse,
BlockCommunity,
BlockPerson,
CommentId,
CommentReplyResponse,
CommentResponse,
CommunityResponse,
@ -73,6 +74,7 @@ import {
enableDownvotes,
enableNsfw,
fetchLimit,
getCommentParentId,
getDataTypeString,
getPageFromString,
getQueryParams,
@ -108,6 +110,7 @@ interface State {
commentsRes: RequestState<GetCommentsResponse>;
siteRes: GetSiteResponse;
showSidebarMobile: boolean;
finished: Map<CommentId, boolean | undefined>;
}
interface CommunityProps {
@ -147,6 +150,7 @@ export class Community extends Component<
commentsRes: { state: "empty" },
siteRes: this.isoData.site_res,
showSidebarMobile: false,
finished: new Map(),
};
constructor(props: RouteComponentProps<{ name: string }>, context: any) {
@ -445,6 +449,7 @@ export class Community extends Component<
<CommentNodes
nodes={commentsToFlatNodes(this.state.commentsRes.data.comments)}
viewType={CommentViewType.Flat}
finished={this.state.finished}
noIndent
showContext
enableDownvotes={enableDownvotes(site_res)}
@ -706,16 +711,7 @@ export class Community extends Component<
const createCommentRes = await apiWrapper(
HttpService.client.createComment(form)
);
this.setState(s => {
if (
s.commentsRes.state == "success" &&
createCommentRes.state == "success"
) {
s.commentsRes.data.comments.unshift(createCommentRes.data.comment_view);
}
return s;
});
this.createAndUpdateComments(createCommentRes);
}
async handleEditComment(form: EditComment) {
@ -924,6 +920,22 @@ export class Community extends Component<
res.data.comment_view,
s.commentsRes.data.comments
);
s.finished.set(res.data.comment_view.comment.id, true);
}
return s;
});
}
createAndUpdateComments(res: RequestState<CommentResponse>) {
this.setState(s => {
if (s.commentsRes.state == "success" && res.state == "success") {
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;
});

View file

@ -10,6 +10,7 @@ import {
BanPerson,
BanPersonResponse,
BlockPerson,
CommentId,
CommentReplyResponse,
CommentResponse,
CreateComment,
@ -67,6 +68,7 @@ import {
enableDownvotes,
enableNsfw,
fetchLimit,
getCommentParentId,
getDataTypeString,
getPageFromString,
getQueryParams,
@ -108,6 +110,7 @@ interface HomeState {
subscribedCollapsed: boolean;
tagline?: string;
siteRes: GetSiteResponse;
finished: Map<CommentId, boolean | undefined>;
}
interface HomeProps {
@ -186,6 +189,7 @@ export class Home extends Component<any, HomeState> {
showTrendingMobile: false,
showSidebarMobile: false,
subscribedCollapsed: false,
finished: new Map(),
};
constructor(props: any, context: any) {
@ -646,6 +650,7 @@ export class Home extends Component<any, HomeState> {
<CommentNodes
nodes={commentsToFlatNodes(comments)}
viewType={CommentViewType.Flat}
finished={this.state.finished}
noIndent
showCommunity
showContext
@ -864,15 +869,7 @@ export class Home extends Component<any, HomeState> {
HttpService.client.createComment(form)
);
this.setState(s => {
if (
s.commentsRes.state == "success" &&
createCommentRes.state == "success"
) {
s.commentsRes.data.comments.unshift(createCommentRes.data.comment_view);
}
return s;
});
this.createAndUpdateComments(createCommentRes);
}
async handleEditComment(form: EditComment) {
@ -1057,6 +1054,22 @@ export class Home extends Component<any, HomeState> {
res.data.comment_view,
s.commentsRes.data.comments
);
s.finished.set(res.data.comment_view.comment.id, true);
}
return s;
});
}
createAndUpdateComments(res: RequestState<CommentResponse>) {
this.setState(s => {
if (s.commentsRes.state == "success" && res.state == "success") {
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;
});

View file

@ -7,6 +7,7 @@ import {
BanPerson,
BanPersonResponse,
BlockPerson,
CommentId,
CommentReplyResponse,
CommentReplyView,
CommentReportResponse,
@ -64,6 +65,7 @@ import {
editPrivateMessages,
enableDownvotes,
fetchLimit,
getCommentParentId,
isBrowser,
isInitialRoute,
myAuth,
@ -114,6 +116,7 @@ interface InboxState {
sort: CommentSortType;
page: number;
siteRes: GetSiteResponse;
finished: Map<CommentId, boolean | undefined>;
}
export class Inbox extends Component<any, InboxState> {
@ -128,6 +131,7 @@ export class Inbox extends Component<any, InboxState> {
mentionsRes: { state: "empty" },
messagesRes: { state: "empty" },
markAllAsReadRes: { state: "empty" },
finished: new Map(),
};
constructor(props: any, context: any) {
@ -434,6 +438,7 @@ export class Inbox extends Component<any, InboxState> {
{ comment_view: i.view as CommentView, children: [], depth: 0 },
]}
viewType={CommentViewType.Flat}
finished={this.state.finished}
noIndent
markable
showCommunity
@ -472,6 +477,7 @@ export class Inbox extends Component<any, InboxState> {
depth: 0,
},
]}
finished={this.state.finished}
viewType={CommentViewType.Flat}
noIndent
markable
@ -529,7 +535,9 @@ export class Inbox extends Component<any, InboxState> {
</h5>
);
} else {
return <div>{this.buildCombined().map(this.renderReplyType)}</div>;
return (
<div>{this.buildCombined().map(r => this.renderReplyType(r))}</div>
);
}
}
@ -548,6 +556,7 @@ export class Inbox extends Component<any, InboxState> {
<CommentNodes
nodes={commentsToFlatNodes(replies)}
viewType={CommentViewType.Flat}
finished={this.state.finished}
noIndent
markable
showCommunity
@ -597,6 +606,7 @@ export class Inbox extends Component<any, InboxState> {
key={umv.person_mention.id}
nodes={[{ comment_view: umv, children: [], depth: 0 }]}
viewType={CommentViewType.Flat}
finished={this.state.finished}
noIndent
markable
showCommunity
@ -683,7 +693,7 @@ export class Inbox extends Component<any, InboxState> {
if (auth) {
// It can be /u/me, or /username/1
let repliesForm: GetReplies = {
sort: "New",
sort,
unread_only: true,
page: 1,
limit: fetchLimit,
@ -772,7 +782,7 @@ export class Inbox extends Component<any, InboxState> {
),
});
if (this.state.markAllAsReadRes.state == "success") {
if (i.state.markAllAsReadRes.state == "success") {
i.setState({
repliesRes: { state: "empty" },
mentionsRes: { state: "empty" },
@ -819,7 +829,8 @@ export class Inbox extends Component<any, InboxState> {
const res = await apiWrapper(HttpService.client.createComment(form));
if (res.state == "success") {
toast(i18n.t("created"));
toast(i18n.t("reply_sent"));
this.findAndUpdateComment(res);
}
}
@ -828,6 +839,7 @@ export class Inbox extends Component<any, InboxState> {
if (res.state == "success") {
toast(i18n.t("edit"));
this.findAndUpdateComment(res);
}
}
@ -835,6 +847,7 @@ export class Inbox extends Component<any, InboxState> {
const res = await apiWrapper(HttpService.client.deleteComment(form));
if (res.state == "success") {
toast(i18n.t("deleted"));
this.findAndUpdateComment(res);
}
}
@ -842,6 +855,7 @@ export class Inbox extends Component<any, InboxState> {
const res = await apiWrapper(HttpService.client.removeComment(form));
if (res.state == "success") {
toast(i18n.t("remove_comment"));
this.findAndUpdateComment(res);
}
}
@ -1026,6 +1040,11 @@ export class Inbox extends Component<any, InboxState> {
s.mentionsRes.data.mentions
);
}
// Set finished for the parent
s.finished.set(
getCommentParentId(res.data.comment_view.comment) ?? 0,
true
);
return s;
});
}

View file

@ -5,6 +5,7 @@ import {
BanFromCommunity,
BanPerson,
BlockPerson,
CommentId,
CommentView,
CreateComment,
CreateCommentLike,
@ -42,6 +43,7 @@ import { PostListing } from "../post/post-listing";
interface PersonDetailsProps {
personRes: GetPersonDetailsResponse;
finished: Map<CommentId, boolean | undefined>;
admins: PersonView[];
allLanguages: Language[];
siteLanguages: number[];
@ -147,6 +149,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
key={i.id}
nodes={[{ comment_view: c, children: [], depth: 0 }]}
viewType={CommentViewType.Flat}
finished={this.props.finished}
admins={this.props.admins}
noBorder
noIndent
@ -255,6 +258,7 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
nodes={commentsToFlatNodes(this.props.personRes.comments)}
viewType={CommentViewType.Flat}
admins={this.props.admins}
finished={this.props.finished}
noIndent
showCommunity
showContext

View file

@ -11,6 +11,7 @@ import {
BanPerson,
BanPersonResponse,
BlockPerson,
CommentId,
CommentReplyResponse,
CommentResponse,
Community,
@ -65,6 +66,7 @@ import {
enableNsfw,
fetchLimit,
futureDaysToUnixTime,
getCommentParentId,
getPageFromString,
getQueryParams,
getQueryString,
@ -100,6 +102,7 @@ interface ProfileState {
showBanDialog: boolean;
removeData: boolean;
siteRes: GetSiteResponse;
finished: Map<CommentId, boolean | undefined>;
}
interface ProfileProps {
@ -163,6 +166,7 @@ export class Profile extends Component<
siteRes: this.isoData.site_res,
showBanDialog: false,
removeData: false,
finished: new Map(),
};
constructor(props: RouteComponentProps<{ username: string }>, context: any) {
@ -333,6 +337,7 @@ export class Profile extends Component<
sort={sort}
page={page}
limit={fetchLimit}
finished={this.state.finished}
enableDownvotes={enableDownvotes(siteRes)}
enableNsfw={enableNsfw(siteRes)}
view={view}
@ -842,16 +847,7 @@ export class Profile extends Component<
const createCommentRes = await apiWrapper(
HttpService.client.createComment(form)
);
this.setState(s => {
if (
s.personRes.state == "success" &&
createCommentRes.state == "success"
) {
s.personRes.data.comments.unshift(createCommentRes.data.comment_view);
}
return s;
});
this.createAndUpdateComments(createCommentRes);
}
async handleEditComment(form: EditComment) {
@ -1033,6 +1029,21 @@ export class Profile extends Component<
res.data.comment_view,
s.personRes.data.comments
);
s.finished.set(res.data.comment_view.comment.id, true);
}
return s;
});
}
createAndUpdateComments(res: RequestState<CommentResponse>) {
this.setState(s => {
if (s.personRes.state == "success" && res.state == "success") {
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;
});

View file

@ -17,7 +17,6 @@ import {
ResolvePostReport,
ResolvePrivateMessageReport,
} from "lemmy-js-client";
import { Subscription } from "rxjs";
import { i18n } from "../../i18next";
import { InitialFetchRequest } from "../../interfaces";
import { HttpService, UserService } from "../../services";
@ -82,7 +81,6 @@ interface ReportsState {
export class Reports extends Component<any, ReportsState> {
private isoData = setIsoData(this.context);
private subscription?: Subscription;
state: ReportsState = {
commentReportsRes: { state: "empty" },
postReportsRes: { state: "empty" },
@ -130,9 +128,9 @@ export class Reports extends Component<any, ReportsState> {
}
}
componentWillUnmount() {
if (isBrowser()) {
this.subscription?.unsubscribe();
async componentDidMount() {
if (!isInitialRoute(this.isoData, this.context)) {
await this.refetch();
}
}
@ -469,14 +467,14 @@ export class Reports extends Component<any, ReportsState> {
await this.refetch();
}
handleUnreadOrAllChange(i: Reports, event: any) {
async handleUnreadOrAllChange(i: Reports, event: any) {
i.setState({ unreadOrAll: Number(event.target.value), page: 1 });
i.refetch();
await i.refetch();
}
handleMessageTypeChange(i: Reports, event: any) {
async handleMessageTypeChange(i: Reports, event: any) {
i.setState({ messageType: Number(event.target.value), page: 1 });
i.refetch();
await i.refetch();
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {

View file

@ -1,4 +1,4 @@
import { Component, linkEvent } from "inferno";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { PostReportView, PostView, ResolvePostReport } from "lemmy-js-client";
import { i18n } from "../../i18next";
@ -25,6 +25,14 @@ export class PostReport extends Component<PostReportProps, PostReportState> {
super(props, context);
}
componentWillReceiveProps(
nextProps: Readonly<{ children?: InfernoNode } & PostReportProps>
): void {
if (this.props != nextProps) {
this.setState({ loading: false });
}
}
render() {
let r = this.props.report;
let resolver = r.resolver;

View file

@ -10,6 +10,7 @@ import {
BanPersonResponse,
BlockCommunity,
BlockPerson,
CommentId,
CommentReplyResponse,
CommentResponse,
CommentSortType,
@ -108,6 +109,7 @@ interface PostState {
commentSectionRef?: RefObject<HTMLDivElement>;
showSidebarMobile: boolean;
maxCommentsShown: number;
finished: Map<CommentId, boolean | undefined>;
}
export class Post extends Component<any, PostState> {
@ -124,6 +126,7 @@ export class Post extends Component<any, PostState> {
siteRes: this.isoData.site_res,
showSidebarMobile: false,
maxCommentsShown: commentsShownInterval,
finished: new Map(),
};
constructor(props: any, context: any) {
@ -382,6 +385,7 @@ export class Post extends Component<any, PostState> {
siteLanguages={this.state.siteRes.discussion_languages}
onCreateComment={this.handleCreateComment}
onEditComment={this.handleEditComment}
finished={this.state.finished.get(0)}
/>
<div className="d-block d-md-none">
<button
@ -511,6 +515,7 @@ export class Post extends Component<any, PostState> {
admins={this.state.siteRes.admins}
enableDownvotes={enableDownvotes(this.state.siteRes)}
showContext
finished={this.state.finished}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
@ -600,6 +605,7 @@ export class Post extends Component<any, PostState> {
moderators={res.data.moderators}
admins={this.state.siteRes.admins}
enableDownvotes={enableDownvotes(this.state.siteRes)}
finished={this.state.finished}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
onSaveComment={this.handleSaveComment}
@ -782,16 +788,7 @@ export class Post extends Component<any, PostState> {
const createCommentRes = await apiWrapper(
HttpService.client.createComment(form)
);
this.setState(s => {
if (
s.commentsRes.state == "success" &&
createCommentRes.state == "success"
) {
s.commentsRes.data.comments.unshift(createCommentRes.data.comment_view);
}
return s;
});
this.createAndUpdateComments(createCommentRes);
}
async handleEditComment(form: EditComment) {
@ -1021,6 +1018,21 @@ export class Post extends Component<any, PostState> {
}
}
createAndUpdateComments(res: RequestState<CommentResponse>) {
this.setState(s => {
if (s.commentsRes.state == "success" && res.state == "success") {
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;
});
}
findAndUpdateComment(res: RequestState<CommentResponse>) {
this.setState(s => {
if (s.commentsRes.state == "success" && res.state == "success") {
@ -1028,6 +1040,7 @@ export class Post extends Component<any, PostState> {
res.data.comment_view,
s.commentsRes.data.comments
);
s.finished.set(res.data.comment_view.comment.id, true);
}
return s;
});

View file

@ -1,5 +1,6 @@
import { Component } from "inferno";
import {
CreatePrivateMessage as CreatePrivateMessageI,
GetPersonDetails,
GetPersonDetailsResponse,
GetSiteResponse,
@ -151,10 +152,14 @@ export class CreatePrivateMessage extends Component<
);
}
handlePrivateMessageCreate() {
toast(i18n.t("message_sent"));
async handlePrivateMessageCreate(form: CreatePrivateMessageI) {
const res = await apiWrapper(HttpService.client.createPrivateMessage(form));
// Navigate to the front
this.context.router.history.push("/");
if (res.state == "success") {
toast(i18n.t("message_sent"));
// Navigate to the front
this.context.router.history.push("/");
}
}
}

View file

@ -1,4 +1,4 @@
import { Component, linkEvent } from "inferno";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { Prompt } from "inferno-router";
import {
@ -56,12 +56,11 @@ export class PrivateMessageForm extends Component<
setupTippy();
}
// TODO what is this
componentDidUpdate() {
if (!this.state.loading && this.state.content) {
window.onbeforeunload = () => true;
} else {
window.onbeforeunload = null;
componentWillReceiveProps(
nextProps: Readonly<{ children?: InfernoNode } & PrivateMessageFormProps>
): void {
if (this.props != nextProps) {
this.setState({ loading: false, content: undefined, previewMode: false });
}
}

View file

@ -1,4 +1,4 @@
import { Component, linkEvent } from "inferno";
import { Component, InfernoNode, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
PrivateMessageReportView,
@ -27,6 +27,14 @@ export class PrivateMessageReport extends Component<Props, State> {
super(props, context);
}
componentWillReceiveProps(
nextProps: Readonly<{ children?: InfernoNode } & Props>
): void {
if (this.props != nextProps) {
this.setState({ loading: false });
}
}
render() {
let r = this.props.report;
let pmr = r.private_message_report;

View file

@ -1,4 +1,4 @@
import { Component, linkEvent } from "inferno";
import { Component, InfernoNode, linkEvent } from "inferno";
import {
CreatePrivateMessage,
CreatePrivateMessageReport,
@ -64,6 +64,23 @@ 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,
reportLoading: false,
});
}
}
render() {
let message_view = this.props.private_message_view;
let otherPerson: Person = this.mine

View file

@ -657,6 +657,7 @@ export class Search extends Component<any, SearchState> {
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
// All of these are unused, since its viewonly
finished={new Map()}
onSaveComment={() => {}}
onBlockPerson={() => {}}
onDeleteComment={() => {}}
@ -717,6 +718,7 @@ export class Search extends Component<any, SearchState> {
allLanguages={siteRes.all_languages}
siteLanguages={siteRes.discussion_languages}
// All of these are unused, since its viewonly
finished={new Map()}
onSaveComment={() => {}}
onBlockPerson={() => {}}
onDeleteComment={() => {}}