From b64f47cfe9084c04a9ec6b8e62ac448f302e2600 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 4 Jan 2023 11:56:24 -0500 Subject: [PATCH] Removing monads. Fixes #884 (#886) * Removing monads. Fixes #884 * Fixing post fetching. * Dont show not_logged_in error for navbar. * Adding the lemmy-js-client RC. * Fixing registration application mode --- lemmy-translations | 2 +- package.json | 5 +- src/client/index.tsx | 10 +- src/server/index.tsx | 35 +- src/shared/components/app/app.tsx | 44 +- src/shared/components/app/footer.tsx | 2 +- src/shared/components/app/navbar.tsx | 299 ++--- src/shared/components/app/theme.tsx | 10 +- .../components/comment/comment-form.tsx | 131 +- .../components/comment/comment-node.tsx | 1125 +++++++++-------- .../components/comment/comment-nodes.tsx | 11 +- .../components/comment/comment-report.tsx | 53 +- .../components/common/banner-icon-header.tsx | 31 +- .../components/common/comment-sort-select.tsx | 5 +- .../components/common/data-type-select.tsx | 5 +- src/shared/components/common/html-tags.tsx | 35 +- .../components/common/image-upload-form.tsx | 50 +- .../components/common/language-select.tsx | 27 +- .../components/common/listing-type-select.tsx | 9 +- .../components/common/markdown-textarea.tsx | 193 ++- src/shared/components/common/moment-time.tsx | 20 +- .../common/registration-application.tsx | 119 +- src/shared/components/common/sort-select.tsx | 5 +- .../components/community/communities.tsx | 207 ++- .../components/community/community-form.tsx | 233 ++-- .../components/community/community-link.tsx | 11 +- src/shared/components/community/community.tsx | 516 ++++---- .../components/community/create-community.tsx | 17 +- src/shared/components/community/sidebar.tsx | 218 ++-- src/shared/components/home/admin-settings.tsx | 52 +- src/shared/components/home/home.tsx | 323 ++--- src/shared/components/home/instances.tsx | 70 +- src/shared/components/home/legal.tsx | 16 +- src/shared/components/home/login.tsx | 65 +- src/shared/components/home/setup.tsx | 69 +- src/shared/components/home/signup.tsx | 262 ++-- src/shared/components/home/site-form.tsx | 570 ++++----- src/shared/components/home/site-sidebar.tsx | 34 +- src/shared/components/modlog.tsx | 358 +++--- src/shared/components/person/inbox.tsx | 534 ++++---- .../components/person/password-change.tsx | 51 +- .../components/person/person-details.tsx | 17 +- .../components/person/person-listing.tsx | 14 +- src/shared/components/person/profile.tsx | 895 ++++++------- .../person/registration-applications.tsx | 99 +- src/shared/components/person/reports.tsx | 284 ++--- src/shared/components/person/settings.tsx | 387 +++--- src/shared/components/person/verify-email.tsx | 18 +- src/shared/components/post/create-post.tsx | 188 ++- src/shared/components/post/metadata-card.tsx | 116 +- src/shared/components/post/post-form.tsx | 564 ++++----- src/shared/components/post/post-listing.tsx | 796 ++++++------ src/shared/components/post/post-listings.tsx | 59 +- src/shared/components/post/post-report.tsx | 55 +- src/shared/components/post/post.tsx | 701 +++++----- .../create-private-message.tsx | 93 +- .../private_message/private-message-form.tsx | 93 +- .../private-message-report.tsx | 52 +- .../private_message/private-message.tsx | 92 +- src/shared/components/search.tsx | 420 +++--- src/shared/interfaces.ts | 11 +- src/shared/routes.ts | 3 + src/shared/services/UserService.ts | 41 +- src/shared/utils.ts | 548 +++----- tsconfig.json | 2 +- yarn.lock | 26 +- 66 files changed, 5171 insertions(+), 6235 deletions(-) diff --git a/lemmy-translations b/lemmy-translations index c970056..975c922 160000 --- a/lemmy-translations +++ b/lemmy-translations @@ -1 +1 @@ -Subproject commit c97005696d132acf2cad3506df4f3c2256142349 +Subproject commit 975c922271f27920aef51a2c3ae9f24714c44004 diff --git a/package.json b/package.json index 54732be..ff20ab6 100644 --- a/package.json +++ b/package.json @@ -23,13 +23,11 @@ "@babel/preset-env": "7.19.3", "@babel/preset-typescript": "^7.18.6", "@babel/runtime": "^7.18.9", - "@sniptt/monads": "^0.5.10", "autosize": "^5.0.1", "babel-loader": "^8.2.5", "babel-plugin-inferno": "^6.5.0", "check-password-strength": "^2.0.7", "choices.js": "^10.1.0", - "class-transformer": "^0.5.1", "classnames": "^2.3.1", "clean-webpack-plugin": "^4.0.0", "copy-webpack-plugin": "^11.0.0", @@ -47,7 +45,7 @@ "inferno-server": "^8.0.5", "isomorphic-cookie": "^1.2.4", "jwt-decode": "^3.1.2", - "lemmy-js-client": "0.17.0-rc.57", + "lemmy-js-client": "0.17.0-rc.61", "markdown-it": "^13.0.1", "markdown-it-container": "^3.0.0", "markdown-it-footnote": "^3.0.3", @@ -57,7 +55,6 @@ "mini-css-extract-plugin": "^2.6.1", "moment": "^2.29.4", "node-fetch": "^2.6.1", - "reflect-metadata": "^0.1.13", "register-service-worker": "^1.7.2", "run-node-webpack-plugin": "^1.3.0", "rxjs": "^7.5.6", diff --git a/src/client/index.tsx b/src/client/index.tsx index 3838dca..a96e6bd 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -1,10 +1,9 @@ import { hydrate } from "inferno-hydrate"; import { BrowserRouter } from "inferno-router"; -import { GetSiteResponse } from "lemmy-js-client"; import { App } from "../shared/components/app/app"; -import { convertWindowJson, initializeSite } from "../shared/utils"; +import { initializeSite } from "../shared/utils"; -const site = convertWindowJson(GetSiteResponse, window.isoData.site_res); +const site = window.isoData.site_res; initializeSite(site); const wrapper = ( @@ -13,4 +12,7 @@ const wrapper = ( ); -hydrate(wrapper, document.getElementById("root")); +let root = document.getElementById("root"); +if (root) { + hydrate(wrapper, root); +} diff --git a/src/server/index.tsx b/src/server/index.tsx index 7d6200e..048e702 100644 --- a/src/server/index.tsx +++ b/src/server/index.tsx @@ -1,5 +1,3 @@ -import { None, Option } from "@sniptt/monads"; -import { serialize as serializeO } from "class-transformer"; import express from "express"; import fs from "fs"; import { IncomingHttpHeaders } from "http"; @@ -7,7 +5,7 @@ import { Helmet } from "inferno-helmet"; import { matchPath, StaticRouter } from "inferno-router"; import { renderToString } from "inferno-server"; import IsomorphicCookie from "isomorphic-cookie"; -import { GetSite, GetSiteResponse, LemmyHttp, toOption } from "lemmy-js-client"; +import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client"; import path from "path"; import process from "process"; import serialize from "serialize-javascript"; @@ -114,11 +112,11 @@ server.get("/css/themelist", async (_req, res) => { // server.use(cookieParser()); server.get("/*", async (req, res) => { try { - const activeRoute = routes.find(route => matchPath(req.path, route)) || {}; + const activeRoute = routes.find(route => matchPath(req.path, route)); const context = {} as any; - let auth: Option = toOption(IsomorphicCookie.load("jwt", req)); + let auth: string | undefined = IsomorphicCookie.load("jwt", req); - let getSiteForm = new GetSite({ auth }); + let getSiteForm: GetSite = { auth }; let promises: Promise[] = []; @@ -138,14 +136,14 @@ server.get("/*", async (req, res) => { console.error( "Incorrect JWT token, skipping auth so frontend can remove jwt cookie" ); - getSiteForm.auth = None; - initialFetchReq.auth = None; + getSiteForm.auth = undefined; + initialFetchReq.auth = undefined; try_site = await initialFetchReq.client.getSite(getSiteForm); } let site: GetSiteResponse = try_site; initializeSite(site); - if (activeRoute.fetchInitialData) { + if (activeRoute?.fetchInitialData) { promises.push(...activeRoute.fetchInitialData(initialFetchReq)); } @@ -193,7 +191,7 @@ server.get("/*", async (req, res) => { - + @@ -246,14 +244,17 @@ server.listen(Number(port), hostname, () => { function setForwardedHeaders(headers: IncomingHttpHeaders): { [key: string]: string; } { - let out = { - host: headers.host, - }; - if (headers["x-real-ip"]) { - out["x-real-ip"] = headers["x-real-ip"]; + let out: { [key: string]: string } = {}; + if (headers.host) { + out.host = headers.host; } - if (headers["x-forwarded-for"]) { - out["x-forwarded-for"] = headers["x-forwarded-for"]; + let realIp = headers["x-real-ip"]; + if (realIp) { + out["x-real-ip"] = realIp as string; + } + let forwardedFor = headers["x-forwarded-for"]; + if (forwardedFor) { + out["x-forwarded-for"] = forwardedFor as string; } return out; diff --git a/src/shared/components/app/app.tsx b/src/shared/components/app/app.tsx index a788636..45c67b3 100644 --- a/src/shared/components/app/app.tsx +++ b/src/shared/components/app/app.tsx @@ -19,37 +19,37 @@ export class App extends Component { render() { let siteRes = this.isoData.site_res; let siteView = siteRes.site_view; + let icon = siteView.site.icon; return ( <>
- {siteView.site.icon.match({ - some: icon => ( - - - - - ), - none: <>, - })} + {icon && ( + + + + + )}
- {routes.map(({ path, exact, component: C, ...rest }) => ( - } - /> - ))} + {routes.map( + ({ path, exact, component: Component, ...rest }) => ( + } + /> + ) + )} } />
diff --git a/src/shared/components/app/footer.tsx b/src/shared/components/app/footer.tsx index 8a7f3bd..a62a8ac 100644 --- a/src/shared/components/app/footer.tsx +++ b/src/shared/components/app/footer.tsx @@ -32,7 +32,7 @@ export class Footer extends Component { {i18n.t("modlog")} - {this.props.site.site_view.local_site.legal_information.isSome() && ( + {this.props.site.site_view.local_site.legal_information && (
  • {i18n.t("legal_information")} diff --git a/src/shared/components/app/navbar.tsx b/src/shared/components/app/navbar.tsx index 06da94d..d758af6 100644 --- a/src/shared/components/app/navbar.tsx +++ b/src/shared/components/app/navbar.tsx @@ -1,4 +1,3 @@ -import { None } from "@sniptt/monads"; import { Component, createRef, linkEvent, RefObject } from "inferno"; import { NavLink } from "inferno-router"; import { @@ -20,10 +19,10 @@ import { i18n } from "../../i18next"; import { UserService, WebSocketService } from "../../services"; import { amAdmin, - auth, canCreateCommunity, donateLemmyUrl, isBrowser, + myAuth, notifyComment, notifyPrivateMessage, numToSI, @@ -57,7 +56,7 @@ export class Navbar extends Component { private unreadReportCountSub: Subscription; private unreadApplicationCountSub: Subscription; private searchTextField: RefObject; - emptyState: NavbarState = { + state: NavbarState = { unreadInboxCount: 0, unreadReportCount: 0, unreadApplicationCount: 0, @@ -70,7 +69,6 @@ export class Navbar extends Component { constructor(props: any, context: any) { super(props, context); - this.state = this.emptyState; this.parseMessage = this.parseMessage.bind(this); this.subscription = wsSubscribe(this.parseMessage); @@ -82,11 +80,12 @@ export class Navbar extends Component { this.searchTextField = createRef(); // On the first load, check the unreads - if (UserService.Instance.myUserInfo.isSome()) { + let auth = myAuth(false); + if (auth && UserService.Instance.myUserInfo) { this.requestNotificationPermission(); WebSocketService.Instance.send( wsClient.userJoin({ - auth: auth().unwrap(), + auth, }) ); @@ -143,22 +142,22 @@ export class Navbar extends Component { // TODO class active corresponding to current page navbar() { let siteView = this.props.siteRes.site_view; + let person = UserService.Instance.myUserInfo?.local_user_view.person; return (
  • + )} + + + )} ) : (
      @@ -516,11 +503,9 @@ export class Navbar extends Component { } get moderatesSomething(): boolean { - return ( - amAdmin() || - UserService.Instance.myUserInfo.map(m => m.moderates).unwrapOr([]) - .length > 0 - ); + let mods = UserService.Instance.myUserInfo?.moderates; + let moderatesS = (mods && mods.length > 0) || false; + return amAdmin() || moderatesS; } handleToggleExpandNavbar(i: Navbar) { @@ -544,9 +529,9 @@ export class Navbar extends Component { event.preventDefault(); i.setState({ toggleSearch: true }); - i.searchTextField.current.focus(); - const offsetWidth = i.searchTextField.current.offsetWidth; - if (i.state.searchParam && offsetWidth > 100) { + i.searchTextField.current?.focus(); + const offsetWidth = i.searchTextField.current?.offsetWidth; + if (i.state.searchParam && offsetWidth && offsetWidth > 100) { i.updateUrl(); } } @@ -576,109 +561,91 @@ export class Navbar extends Component { return; } else if (msg.reconnect) { console.log(i18n.t("websocket_reconnected")); - if (UserService.Instance.myUserInfo.isSome()) { + let auth = myAuth(false); + if (UserService.Instance.myUserInfo && auth) { WebSocketService.Instance.send( wsClient.userJoin({ - auth: auth().unwrap(), + auth, }) ); this.fetchUnreads(); } } else if (op == UserOperation.GetUnreadCount) { - let data = wsJsonToRes( - msg, - GetUnreadCountResponse - ); + let data = wsJsonToRes(msg); this.setState({ unreadInboxCount: data.replies + data.mentions + data.private_messages, }); this.sendUnreadCount(); } else if (op == UserOperation.GetReportCount) { - let data = wsJsonToRes( - msg, - GetReportCountResponse - ); + let data = wsJsonToRes(msg); this.setState({ unreadReportCount: data.post_reports + data.comment_reports + - data.private_message_reports.unwrapOr(0), + (data.private_message_reports ?? 0), }); this.sendReportUnread(); } else if (op == UserOperation.GetUnreadRegistrationApplicationCount) { - let data = wsJsonToRes( - msg, - GetUnreadRegistrationApplicationCountResponse - ); + let data = + wsJsonToRes(msg); this.setState({ unreadApplicationCount: data.registration_applications }); this.sendApplicationUnread(); } else if (op == UserOperation.CreateComment) { - let data = wsJsonToRes(msg, CommentResponse); - - UserService.Instance.myUserInfo.match({ - some: mui => { - if (data.recipient_ids.includes(mui.local_user_view.local_user.id)) { - this.setState({ - unreadInboxCount: this.state.unreadInboxCount + 1, - }); - this.sendUnreadCount(); - notifyComment(data.comment_view, this.context.router); - } - }, - none: void 0, - }); + let data = wsJsonToRes(msg); + let mui = UserService.Instance.myUserInfo; + if ( + mui && + data.recipient_ids.includes(mui.local_user_view.local_user.id) + ) { + this.setState({ + unreadInboxCount: this.state.unreadInboxCount + 1, + }); + this.sendUnreadCount(); + notifyComment(data.comment_view, this.context.router); + } } else if (op == UserOperation.CreatePrivateMessage) { - let data = wsJsonToRes( - msg, - PrivateMessageResponse - ); - - UserService.Instance.myUserInfo.match({ - some: mui => { - if ( - data.private_message_view.recipient.id == - mui.local_user_view.person.id - ) { - this.setState({ - unreadInboxCount: this.state.unreadInboxCount + 1, - }); - this.sendUnreadCount(); - notifyPrivateMessage( - data.private_message_view, - this.context.router - ); - } - }, - none: void 0, - }); + let data = wsJsonToRes(msg); + + if ( + data.private_message_view.recipient.id == + UserService.Instance.myUserInfo?.local_user_view.person.id + ) { + this.setState({ + unreadInboxCount: this.state.unreadInboxCount + 1, + }); + this.sendUnreadCount(); + notifyPrivateMessage(data.private_message_view, this.context.router); + } } } fetchUnreads() { console.log("Fetching inbox unreads..."); - let unreadForm = new GetUnreadCount({ - auth: auth().unwrap(), - }); - WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm)); + let auth = myAuth(); + if (auth) { + let unreadForm: GetUnreadCount = { + auth, + }; + WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm)); - console.log("Fetching reports..."); + console.log("Fetching reports..."); - let reportCountForm = new GetReportCount({ - community_id: None, - auth: auth().unwrap(), - }); - WebSocketService.Instance.send(wsClient.getReportCount(reportCountForm)); + let reportCountForm: GetReportCount = { + auth, + }; + WebSocketService.Instance.send(wsClient.getReportCount(reportCountForm)); - if (amAdmin()) { - console.log("Fetching applications..."); + if (amAdmin()) { + console.log("Fetching applications..."); - let applicationCountForm = new GetUnreadRegistrationApplicationCount({ - auth: auth().unwrap(), - }); - WebSocketService.Instance.send( - wsClient.getUnreadRegistrationApplicationCount(applicationCountForm) - ); + let applicationCountForm: GetUnreadRegistrationApplicationCount = { + auth, + }; + WebSocketService.Instance.send( + wsClient.getUnreadRegistrationApplicationCount(applicationCountForm) + ); + } } } @@ -703,7 +670,7 @@ export class Navbar extends Component { } requestNotificationPermission() { - if (UserService.Instance.myUserInfo.isSome()) { + if (UserService.Instance.myUserInfo) { document.addEventListener("DOMContentLoaded", function () { if (!Notification) { toast(i18n.t("notifications_error"), "danger"); diff --git a/src/shared/components/app/theme.tsx b/src/shared/components/app/theme.tsx index 0f2a083..4510fe2 100644 --- a/src/shared/components/app/theme.tsx +++ b/src/shared/components/app/theme.tsx @@ -9,19 +9,15 @@ interface Props { export class Theme extends Component { render() { let user = UserService.Instance.myUserInfo; - let hasTheme = user - .map(m => m.local_user_view.local_user.theme !== "browser") - .unwrapOr(false); + let hasTheme = user?.local_user_view.local_user.theme !== "browser"; - if (hasTheme) { + if (user && hasTheme) { return ( ); diff --git a/src/shared/components/comment/comment-form.tsx b/src/shared/components/comment/comment-form.tsx index a74cc8b..40650db 100644 --- a/src/shared/components/comment/comment-form.tsx +++ b/src/shared/components/comment/comment-form.tsx @@ -1,4 +1,3 @@ -import { Either, None, Option, Some } from "@sniptt/monads"; import { Component } from "inferno"; import { T } from "inferno-i18next-dess"; import { Link } from "inferno-router"; @@ -16,8 +15,8 @@ import { Subscription } from "rxjs"; import { i18n } from "../../i18next"; import { UserService, WebSocketService } from "../../services"; import { - auth, capitalizeFirstLetter, + myAuth, myFirstDiscussionLanguageId, wsClient, wsSubscribe, @@ -29,7 +28,7 @@ interface CommentFormProps { /** * Can either be the parent, or the editable comment. The right side is a postId. */ - node: Either; + node: CommentNodeI | number; edit?: boolean; disabled?: boolean; focus?: boolean; @@ -41,19 +40,19 @@ interface CommentFormProps { interface CommentFormState { buttonTitle: string; finished: boolean; - formId: Option; + formId?: string; } export class CommentForm extends Component { - private subscription: Subscription; - private emptyState: CommentFormState = { - buttonTitle: this.props.node.isRight() - ? capitalizeFirstLetter(i18n.t("post")) - : this.props.edit - ? capitalizeFirstLetter(i18n.t("save")) - : capitalizeFirstLetter(i18n.t("reply")), + private subscription?: Subscription; + state: CommentFormState = { + buttonTitle: + typeof this.props.node === "number" + ? capitalizeFirstLetter(i18n.t("post")) + : this.props.edit + ? capitalizeFirstLetter(i18n.t("save")) + : capitalizeFirstLetter(i18n.t("reply")), finished: false, - formId: None, }; constructor(props: any, context: any) { @@ -62,50 +61,46 @@ export class CommentForm extends Component { this.handleCommentSubmit = this.handleCommentSubmit.bind(this); this.handleReplyCancel = this.handleReplyCancel.bind(this); - this.state = this.emptyState; - this.parseMessage = this.parseMessage.bind(this); this.subscription = wsSubscribe(this.parseMessage); } componentWillUnmount() { - this.subscription.unsubscribe(); + this.subscription?.unsubscribe(); } render() { - let initialContent = this.props.node.match({ - left: node => - this.props.edit ? Some(node.comment_view.comment.content) : None, - right: () => None, - }); - - let selectedLang = this.props.node - .left() - .map(n => n.comment_view.comment.language_id) - .or( - myFirstDiscussionLanguageId( - this.props.allLanguages, - this.props.siteLanguages, - UserService.Instance.myUserInfo - ) - ); + let initialContent = + typeof this.props.node !== "number" + ? this.props.edit + ? this.props.node.comment_view.comment.content + : undefined + : undefined; + + let selectedLang = + typeof this.props.node !== "number" + ? this.props.node.comment_view.comment.language_id + : myFirstDiscussionLanguageId( + this.props.allLanguages, + this.props.siteLanguages, + UserService.Instance.myUserInfo + ); return (
      - {UserService.Instance.myUserInfo.isSome() ? ( + {UserService.Instance.myUserInfo ? ( @@ -125,55 +120,55 @@ export class CommentForm extends Component { } handleCommentSubmit(msg: { - val: Option; + val: string; formId: string; - languageId: Option; + languageId?: number; }) { let content = msg.val; let language_id = msg.languageId; - this.setState({ formId: Some(msg.formId) }); + let node = this.props.node; + + this.setState({ formId: msg.formId }); - this.props.node.match({ - left: node => { + let auth = myAuth(); + if (auth) { + if (typeof node === "number") { + let postId = node; + let form: CreateComment = { + content, + form_id: this.state.formId, + post_id: postId, + language_id, + auth, + }; + WebSocketService.Instance.send(wsClient.createComment(form)); + } else { if (this.props.edit) { - let form = new EditComment({ + let form: EditComment = { content, - distinguished: None, form_id: this.state.formId, comment_id: node.comment_view.comment.id, language_id, - auth: auth().unwrap(), - }); + auth, + }; WebSocketService.Instance.send(wsClient.editComment(form)); } else { - let form = new CreateComment({ - content: content.unwrap(), + let form: CreateComment = { + content, form_id: this.state.formId, post_id: node.comment_view.post.id, - parent_id: Some(node.comment_view.comment.id), + parent_id: node.comment_view.comment.id, language_id, - auth: auth().unwrap(), - }); + auth, + }; WebSocketService.Instance.send(wsClient.createComment(form)); } - }, - right: postId => { - let form = new CreateComment({ - content: content.unwrap(), - form_id: this.state.formId, - post_id: postId, - parent_id: None, - language_id, - auth: auth().unwrap(), - }); - WebSocketService.Instance.send(wsClient.createComment(form)); - }, - }); - this.setState(this.state); + } + } } handleReplyCancel() { - this.props.onReplyCancel(); + this.props.onReplyCancel?.(); } parseMessage(msg: any) { @@ -181,15 +176,15 @@ export class CommentForm extends Component { console.log(msg); // Only do the showing and hiding if logged in - if (UserService.Instance.myUserInfo.isSome()) { + if (UserService.Instance.myUserInfo) { if ( op == UserOperation.CreateComment || op == UserOperation.EditComment ) { - let data = wsJsonToRes(msg, CommentResponse); + let data = wsJsonToRes(msg); // This only finishes this form, if the randomly generated form_id matches the one received - if (this.state.formId.unwrapOr("") == data.form_id.unwrapOr("")) { + if (this.state.formId == data.form_id) { this.setState({ finished: true }); // Necessary because it broke tribute for some reason diff --git a/src/shared/components/comment/comment-node.tsx b/src/shared/components/comment/comment-node.tsx index e37c68e..50da456 100644 --- a/src/shared/components/comment/comment-node.tsx +++ b/src/shared/components/comment/comment-node.tsx @@ -1,4 +1,3 @@ -import { Left, None, Option, Some } from "@sniptt/monads"; import classNames from "classnames"; import { Component, linkEvent } from "inferno"; import { Link } from "inferno-router"; @@ -27,7 +26,6 @@ import { PurgePerson, RemoveComment, SaveComment, - toUndefined, TransferCommunity, } from "lemmy-js-client"; import moment from "moment"; @@ -36,7 +34,6 @@ import { BanType, CommentViewType, PurgeType } from "../../interfaces"; import { UserService, WebSocketService } from "../../services"; import { amCommunityCreator, - auth, canAdmin, canMod, colorList, @@ -47,6 +44,7 @@ import { isMod, mdToHtml, mdToHtmlNoImages, + myAuth, numToSI, setupTippy, showScores, @@ -63,14 +61,14 @@ interface CommentNodeState { showReply: boolean; showEdit: boolean; showRemoveDialog: boolean; - removeReason: Option; + removeReason?: string; showBanDialog: boolean; removeData: boolean; - banReason: Option; - banExpireDays: Option; + banReason?: string; + banExpireDays?: number; banType: BanType; showPurgeDialog: boolean; - purgeReason: Option; + purgeReason?: string; purgeType: PurgeType; purgeLoading: boolean; showConfirmTransferSite: boolean; @@ -81,8 +79,8 @@ interface CommentNodeState { viewSource: boolean; showAdvanced: boolean; showReportDialog: boolean; - reportReason: string; - my_vote: Option; + reportReason?: string; + my_vote?: number; score: number; upvotes: number; downvotes: number; @@ -92,8 +90,8 @@ interface CommentNodeState { interface CommentNodeProps { node: CommentNodeI; - moderators: Option; - admins: Option; + moderators?: CommunityModeratorView[]; + admins?: PersonViewSafe[]; noBorder?: boolean; noIndent?: boolean; viewOnly?: boolean; @@ -101,7 +99,7 @@ interface CommentNodeProps { markable?: boolean; showContext?: boolean; showCommunity?: boolean; - enableDownvotes: boolean; + enableDownvotes?: boolean; viewType: CommentViewType; allLanguages: Language[]; siteLanguages: number[]; @@ -109,19 +107,15 @@ interface CommentNodeProps { } export class CommentNode extends Component { - private emptyState: CommentNodeState = { + state: CommentNodeState = { showReply: false, showEdit: false, showRemoveDialog: false, - removeReason: None, showBanDialog: false, removeData: false, - banReason: None, - banExpireDays: None, banType: BanType.Community, showPurgeDialog: false, purgeLoading: false, - purgeReason: None, purgeType: PurgeType.Person, collapsed: false, viewSource: false, @@ -131,7 +125,6 @@ export class CommentNode extends Component { showConfirmAppointAsMod: false, showConfirmAppointAsAdmin: false, showReportDialog: false, - reportReason: null, my_vote: this.props.node.comment_view.my_vote, score: this.props.node.comment_view.counts.score, upvotes: this.props.node.comment_view.counts.upvotes, @@ -143,7 +136,6 @@ export class CommentNode extends Component { constructor(props: any, context: any) { super(props, context); - this.state = this.emptyState; this.handleReplyCancel = this.handleReplyCancel.bind(this); this.handleCommentUpvote = this.handleCommentUpvote.bind(this); this.handleCommentDownvote = this.handleCommentDownvote.bind(this); @@ -166,37 +158,35 @@ export class CommentNode extends Component { let node = this.props.node; let cv = this.props.node.comment_view; - let purgeTypeText: string; - if (this.state.purgeType == PurgeType.Comment) { - purgeTypeText = i18n.t("purge_comment"); - } else if (this.state.purgeType == PurgeType.Person) { - purgeTypeText = `${i18n.t("purge")} ${cv.creator.name}`; - } + let purgeTypeText = + this.state.purgeType == PurgeType.Comment + ? i18n.t("purge_comment") + : `${i18n.t("purge")} ${cv.creator.name}`; let canMod_ = canMod( + cv.creator.id, this.props.moderators, - this.props.admins, - cv.creator.id + this.props.admins ); let canModOnSelf = canMod( + cv.creator.id, this.props.moderators, this.props.admins, - cv.creator.id, UserService.Instance.myUserInfo, true ); - let canAdmin_ = canAdmin(this.props.admins, cv.creator.id); + let canAdmin_ = canAdmin(cv.creator.id, this.props.admins); let canAdminOnSelf = canAdmin( - this.props.admins, cv.creator.id, + this.props.admins, UserService.Instance.myUserInfo, true ); - let isMod_ = isMod(this.props.moderators, cv.creator.id); - let isAdmin_ = isAdmin(this.props.admins, cv.creator.id); + let isMod_ = isMod(cv.creator.id, this.props.moderators); + let isAdmin_ = isAdmin(cv.creator.id, this.props.admins); let amCommunityCreator_ = amCommunityCreator( - this.props.moderators, - cv.creator.id + cv.creator.id, + this.props.moderators ); let borderColor = this.props.node.depth @@ -227,15 +217,15 @@ export class CommentNode extends Component { this.props.node.comment_view.comment.distinguished, })} style={ - !this.props.noIndent && - this.props.node.depth && - `border-left: 2px ${borderColor} solid !important` + !this.props.noIndent && this.props.node.depth + ? `border-left: 2px ${borderColor} solid !important` + : "" } >
      @@ -324,7 +314,7 @@ export class CommentNode extends Component { {/* end of user row */} {this.state.showEdit && ( { )} )} - {UserService.Instance.myUserInfo.isSome() && - !this.props.viewOnly && ( - <> + {UserService.Instance.myUserInfo && !this.props.viewOnly && ( + <> + + {this.props.enableDownvotes && ( - {this.props.enableDownvotes && ( - - )} + )} + + {!this.state.showAdvanced ? ( - {!this.state.showAdvanced ? ( + ) : ( + <> + {!this.myComment && ( + <> + + + + + )} - ) : ( - <> - {!this.myComment && ( - <> - - + + {this.myComment && ( + <> + + + + {(canModOnSelf || canAdminOnSelf) && ( - - )} - - - {this.myComment && ( - <> + + )} + {/* Admins and mods can remove comments */} + {(canMod_ || canAdmin_) && ( + <> + {!cv.comment.removed ? ( + ) : ( - - {(canModOnSelf || canAdminOnSelf) && ( + )} + + )} + {/* Mods can ban from community, and appoint as mods to community */} + {canMod_ && ( + <> + {!isMod_ && + (!cv.creator_banned_from_community ? ( - )} - - )} - {/* Admins and mods can remove comments */} - {(canMod_ || canAdmin_) && ( - <> - {!cv.comment.removed ? ( + ) : ( - ) : ( + ))} + {!cv.creator_banned_from_community && + (!this.state.showConfirmAppointAsMod ? ( - )} - - )} - {/* Mods can ban from community, and appoint as mods to community */} - {canMod_ && ( - <> - {!isMod_ && - (!cv.creator_banned_from_community ? ( + ) : ( + <> - ) : ( - ))} - {!cv.creator_banned_from_community && - (!this.state.showConfirmAppointAsMod ? ( - ) : ( - <> - - - - - ))} - - )} - {/* Community creators and admins can transfer community to another mod */} - {(amCommunityCreator_ || canAdmin_) && - isMod_ && - cv.creator.local && - (!this.state.showConfirmTransferCommunity ? ( + + ))} + + )} + {/* Community creators and admins can transfer community to another mod */} + {(amCommunityCreator_ || canAdmin_) && + isMod_ && + cv.creator.local && + (!this.state.showConfirmTransferCommunity ? ( + + ) : ( + <> + - ) : ( + + + ))} + {/* Admins can ban from all, and appoint other admins */} + {canAdmin_ && ( + <> + {!isAdmin_ && ( <> - - - ))} - {/* Admins can ban from all, and appoint other admins */} - {canAdmin_ && ( - <> - {!isAdmin_ && ( - <> + + {!isBanned(cv.creator) ? ( + ) : ( - - {!isBanned(cv.creator) ? ( - - ) : ( - + )} + + )} + {!isBanned(cv.creator) && + cv.creator.local && + (!this.state.showConfirmAppointAsAdmin ? ( + + ) : ( + <> + - ) : ( - <> - - - - - ))} - - )} - - )} - - )} + + + ))} + + )} + + )} + + )}
      {/* end of button group */}
      @@ -873,7 +856,7 @@ export class CommentNode extends Component { id={`mod-remove-reason-${cv.comment.id}`} className="form-control mr-2" placeholder={i18n.t("reason")} - value={toUndefined(this.state.removeReason)} + value={this.state.removeReason} onInput={linkEvent(this, this.handleModRemoveReasonChange)} />