-Subproject commit c97005696d132acf2cad3506df4f3c2256142349
+Subproject commit 975c922271f27920aef51a2c3ae9f24714c44004
"@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",
"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",
"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",
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 = (
</BrowserRouter>
);
-hydrate(wrapper, document.getElementById("root"));
+let root = document.getElementById("root");
+if (root) {
+ hydrate(wrapper, root);
+}
-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";
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";
// 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<string> = 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<any>[] = [];
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));
}
<!DOCTYPE html>
<html ${helmet.htmlAttributes.toString()} lang="en">
<head>
- <script>window.isoData = ${serializeO(isoData)}</script>
+ <script>window.isoData = ${JSON.stringify(isoData)}</script>
<script>window.lemmyConfig = ${serialize(config)}</script>
<!-- A remote debugging utility for mobile -->
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;
render() {
let siteRes = this.isoData.site_res;
let siteView = siteRes.site_view;
+ let icon = siteView.site.icon;
return (
<>
<Provider i18next={i18n}>
<div id="app">
<Theme defaultTheme={siteView.local_site.default_theme} />
- {siteView.site.icon.match({
- some: icon => (
- <Helmet>
- <link
- id="favicon"
- rel="shortcut icon"
- type="image/x-icon"
- href={icon || favIconUrl}
- />
- <link rel="apple-touch-icon" href={icon || favIconPngUrl} />
- </Helmet>
- ),
- none: <></>,
- })}
+ {icon && (
+ <Helmet>
+ <link
+ id="favicon"
+ rel="shortcut icon"
+ type="image/x-icon"
+ href={icon || favIconUrl}
+ />
+ <link rel="apple-touch-icon" href={icon || favIconPngUrl} />
+ </Helmet>
+ )}
<Navbar siteRes={siteRes} />
<div className="mt-4 p-0 fl-1">
<Switch>
- {routes.map(({ path, exact, component: C, ...rest }) => (
- <Route
- key={path}
- path={path}
- exact={exact}
- render={props => <C {...props} {...rest} />}
- />
- ))}
+ {routes.map(
+ ({ path, exact, component: Component, ...rest }) => (
+ <Route
+ key={path}
+ path={path}
+ exact={exact}
+ render={props => <Component {...props} {...rest} />}
+ />
+ )
+ )}
<Route render={props => <NoMatch {...props} />} />
</Switch>
</div>
{i18n.t("modlog")}
</NavLink>
</li>
- {this.props.site.site_view.local_site.legal_information.isSome() && (
+ {this.props.site.site_view.local_site.legal_information && (
<li className="nav-item">
<NavLink className="nav-link" to="/legal">
{i18n.t("legal_information")}
-import { None } from "@sniptt/monads";
import { Component, createRef, linkEvent, RefObject } from "inferno";
import { NavLink } from "inferno-router";
import {
import { UserService, WebSocketService } from "../../services";
import {
amAdmin,
- auth,
canCreateCommunity,
donateLemmyUrl,
isBrowser,
+ myAuth,
notifyComment,
notifyPrivateMessage,
numToSI,
private unreadReportCountSub: Subscription;
private unreadApplicationCountSub: Subscription;
private searchTextField: RefObject<HTMLInputElement>;
- emptyState: NavbarState = {
+ state: NavbarState = {
unreadInboxCount: 0,
unreadReportCount: 0,
unreadApplicationCount: 0,
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
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,
})
);
// 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 (
<nav className="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3">
<div className="container-lg">
<NavLink
to="/"
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
- title={siteView.site.description.unwrapOr(siteView.site.name)}
+ title={siteView.site.description ?? siteView.site.name}
className="d-flex align-items-center navbar-brand mr-md-3"
>
- {siteView.site.icon.match({
- some: icon => showAvatars() && <PictrsImage src={icon} icon />,
- none: <></>,
- })}
+ {siteView.site.icon && showAvatars() && (
+ <PictrsImage src={siteView.site.icon} icon />
+ )}
{siteView.site.name}
</NavLink>
- {UserService.Instance.myUserInfo.isSome() && (
+ {UserService.Instance.myUserInfo && (
<>
<ul className="navbar-nav ml-auto">
<li className="nav-item">
</li>
</ul>
)}
- {UserService.Instance.myUserInfo.isSome() ? (
+ {UserService.Instance.myUserInfo ? (
<>
<ul className="navbar-nav my-2">
<li className="nav-item">
</li>
</ul>
)}
- {UserService.Instance.myUserInfo
- .map(m => m.local_user_view.person)
- .match({
- some: person => (
- <ul className="navbar-nav">
- <li className="nav-item dropdown">
- <button
- className="nav-link btn btn-link dropdown-toggle"
- onClick={linkEvent(this, this.handleToggleDropdown)}
- id="navbarDropdown"
- role="button"
- aria-expanded="false"
- >
- <span>
- {showAvatars() &&
- person.avatar.match({
- some: avatar => (
- <PictrsImage src={avatar} icon />
- ),
- none: <></>,
- })}
- {person.display_name.unwrapOr(person.name)}
- </span>
- </button>
- {this.state.showDropdown && (
- <div
- className="dropdown-content"
- onMouseLeave={linkEvent(
- this,
- this.handleToggleDropdown
- )}
- >
- <li className="nav-item">
- <NavLink
- to={`/u/${person.name}`}
- className="nav-link"
- title={i18n.t("profile")}
- >
- <Icon icon="user" classes="mr-1" />
- {i18n.t("profile")}
- </NavLink>
- </li>
- <li className="nav-item">
- <NavLink
- to="/settings"
- className="nav-link"
- title={i18n.t("settings")}
- >
- <Icon icon="settings" classes="mr-1" />
- {i18n.t("settings")}
- </NavLink>
- </li>
- <li>
- <hr className="dropdown-divider" />
- </li>
- <li className="nav-item">
- <button
- className="nav-link btn btn-link"
- onClick={linkEvent(
- this,
- this.handleLogoutClick
- )}
- title="test"
- >
- <Icon icon="log-out" classes="mr-1" />
- {i18n.t("logout")}
- </button>
- </li>
- </div>
+ {person && (
+ <ul className="navbar-nav">
+ <li className="nav-item dropdown">
+ <button
+ className="nav-link btn btn-link dropdown-toggle"
+ onClick={linkEvent(this, this.handleToggleDropdown)}
+ id="navbarDropdown"
+ role="button"
+ aria-expanded="false"
+ >
+ <span>
+ {showAvatars() && person.avatar && (
+ <PictrsImage src={person.avatar} icon />
+ )}
+ {person.display_name ?? person.name}
+ </span>
+ </button>
+ {this.state.showDropdown && (
+ <div
+ className="dropdown-content"
+ onMouseLeave={linkEvent(
+ this,
+ this.handleToggleDropdown
)}
- </li>
- </ul>
- ),
- none: <></>,
- })}
+ >
+ <li className="nav-item">
+ <NavLink
+ to={`/u/${person.name}`}
+ className="nav-link"
+ title={i18n.t("profile")}
+ >
+ <Icon icon="user" classes="mr-1" />
+ {i18n.t("profile")}
+ </NavLink>
+ </li>
+ <li className="nav-item">
+ <NavLink
+ to="/settings"
+ className="nav-link"
+ title={i18n.t("settings")}
+ >
+ <Icon icon="settings" classes="mr-1" />
+ {i18n.t("settings")}
+ </NavLink>
+ </li>
+ <li>
+ <hr className="dropdown-divider" />
+ </li>
+ <li className="nav-item">
+ <button
+ className="nav-link btn btn-link"
+ onClick={linkEvent(this, this.handleLogoutClick)}
+ title="test"
+ >
+ <Icon icon="log-out" classes="mr-1" />
+ {i18n.t("logout")}
+ </button>
+ </li>
+ </div>
+ )}
+ </li>
+ </ul>
+ )}
</>
) : (
<ul className="navbar-nav my-2">
}
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) {
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();
}
}
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<GetUnreadCountResponse>(
- msg,
- GetUnreadCountResponse
- );
+ let data = wsJsonToRes<GetUnreadCountResponse>(msg);
this.setState({
unreadInboxCount: data.replies + data.mentions + data.private_messages,
});
this.sendUnreadCount();
} else if (op == UserOperation.GetReportCount) {
- let data = wsJsonToRes<GetReportCountResponse>(
- msg,
- GetReportCountResponse
- );
+ let data = wsJsonToRes<GetReportCountResponse>(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<GetUnreadRegistrationApplicationCountResponse>(
- msg,
- GetUnreadRegistrationApplicationCountResponse
- );
+ let data =
+ wsJsonToRes<GetUnreadRegistrationApplicationCountResponse>(msg);
this.setState({ unreadApplicationCount: data.registration_applications });
this.sendApplicationUnread();
} else if (op == UserOperation.CreateComment) {
- let data = wsJsonToRes<CommentResponse>(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<CommentResponse>(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<PrivateMessageResponse>(
- 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<PrivateMessageResponse>(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)
+ );
+ }
}
}
}
requestNotificationPermission() {
- if (UserService.Instance.myUserInfo.isSome()) {
+ if (UserService.Instance.myUserInfo) {
document.addEventListener("DOMContentLoaded", function () {
if (!Notification) {
toast(i18n.t("notifications_error"), "danger");
export class Theme extends Component<Props> {
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 (
<Helmet>
<link
rel="stylesheet"
type="text/css"
- href={`/css/themes/${
- user.unwrap().local_user_view.local_user.theme
- }.css`}
+ href={`/css/themes/${user.local_user_view.local_user.theme}.css`}
/>
</Helmet>
);
-import { Either, None, Option, Some } from "@sniptt/monads";
import { Component } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
capitalizeFirstLetter,
+ myAuth,
myFirstDiscussionLanguageId,
wsClient,
wsSubscribe,
/**
* Can either be the parent, or the editable comment. The right side is a postId.
*/
- node: Either<CommentNodeI, number>;
+ node: CommentNodeI | number;
edit?: boolean;
disabled?: boolean;
focus?: boolean;
interface CommentFormState {
buttonTitle: string;
finished: boolean;
- formId: Option<string>;
+ formId?: string;
}
export class CommentForm extends Component<CommentFormProps, CommentFormState> {
- 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) {
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 (
<div className="mb-3">
- {UserService.Instance.myUserInfo.isSome() ? (
+ {UserService.Instance.myUserInfo ? (
<MarkdownTextArea
initialContent={initialContent}
initialLanguageId={selectedLang}
showLanguage
- buttonTitle={Some(this.state.buttonTitle)}
- maxLength={None}
+ buttonTitle={this.state.buttonTitle}
finished={this.state.finished}
- replyType={this.props.node.isLeft()}
+ replyType={typeof this.props.node !== "number"}
focus={this.props.focus}
disabled={this.props.disabled}
onSubmit={this.handleCommentSubmit}
onReplyCancel={this.handleReplyCancel}
- placeholder={Some(i18n.t("comment_here"))}
+ placeholder={i18n.t("comment_here")}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
/>
}
handleCommentSubmit(msg: {
- val: Option<string>;
+ val: string;
formId: string;
- languageId: Option<number>;
+ 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) {
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<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(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
-import { Left, None, Option, Some } from "@sniptt/monads";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
PurgePerson,
RemoveComment,
SaveComment,
- toUndefined,
TransferCommunity,
} from "lemmy-js-client";
import moment from "moment";
import { UserService, WebSocketService } from "../../services";
import {
amCommunityCreator,
- auth,
canAdmin,
canMod,
colorList,
isMod,
mdToHtml,
mdToHtmlNoImages,
+ myAuth,
numToSI,
setupTippy,
showScores,
showReply: boolean;
showEdit: boolean;
showRemoveDialog: boolean;
- removeReason: Option<string>;
+ removeReason?: string;
showBanDialog: boolean;
removeData: boolean;
- banReason: Option<string>;
- banExpireDays: Option<number>;
+ banReason?: string;
+ banExpireDays?: number;
banType: BanType;
showPurgeDialog: boolean;
- purgeReason: Option<string>;
+ purgeReason?: string;
purgeType: PurgeType;
purgeLoading: boolean;
showConfirmTransferSite: boolean;
viewSource: boolean;
showAdvanced: boolean;
showReportDialog: boolean;
- reportReason: string;
- my_vote: Option<number>;
+ reportReason?: string;
+ my_vote?: number;
score: number;
upvotes: number;
downvotes: number;
interface CommentNodeProps {
node: CommentNodeI;
- moderators: Option<CommunityModeratorView[]>;
- admins: Option<PersonViewSafe[]>;
+ moderators?: CommunityModeratorView[];
+ admins?: PersonViewSafe[];
noBorder?: boolean;
noIndent?: boolean;
viewOnly?: boolean;
markable?: boolean;
showContext?: boolean;
showCommunity?: boolean;
- enableDownvotes: boolean;
+ enableDownvotes?: boolean;
viewType: CommentViewType;
allLanguages: Language[];
siteLanguages: number[];
}
export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
- 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,
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,
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);
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
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`
+ : ""
}
>
<div
- className={`${
- !this.props.noIndent && this.props.node.depth && "ml-2"
- }`}
+ className={classNames({
+ "ml-2": !this.props.noIndent && this.props.node.depth,
+ })}
>
<div className="d-flex flex-wrap align-items-center text-muted small">
<span className="mr-2">
{/* end of user row */}
{this.state.showEdit && (
<CommentForm
- node={Left(node)}
+ node={node}
edit
onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked}
)}
</button>
)}
- {UserService.Instance.myUserInfo.isSome() &&
- !this.props.viewOnly && (
- <>
+ {UserService.Instance.myUserInfo && !this.props.viewOnly && (
+ <>
+ <button
+ className={`btn btn-link btn-animate ${
+ this.state.my_vote == 1 ? "text-info" : "text-muted"
+ }`}
+ onClick={this.handleCommentUpvote}
+ data-tippy-content={i18n.t("upvote")}
+ aria-label={i18n.t("upvote")}
+ >
+ <Icon icon="arrow-up1" classes="icon-inline" />
+ {showScores() &&
+ this.state.upvotes !== this.state.score && (
+ <span className="ml-1">
+ {numToSI(this.state.upvotes)}
+ </span>
+ )}
+ </button>
+ {this.props.enableDownvotes && (
<button
className={`btn btn-link btn-animate ${
- this.state.my_vote.unwrapOr(0) == 1
- ? "text-info"
+ this.state.my_vote == -1
+ ? "text-danger"
: "text-muted"
}`}
- onClick={this.handleCommentUpvote}
- data-tippy-content={i18n.t("upvote")}
- aria-label={i18n.t("upvote")}
+ onClick={this.handleCommentDownvote}
+ data-tippy-content={i18n.t("downvote")}
+ aria-label={i18n.t("downvote")}
>
- <Icon icon="arrow-up1" classes="icon-inline" />
+ <Icon icon="arrow-down1" classes="icon-inline" />
{showScores() &&
this.state.upvotes !== this.state.score && (
<span className="ml-1">
- {numToSI(this.state.upvotes)}
+ {numToSI(this.state.downvotes)}
</span>
)}
</button>
- {this.props.enableDownvotes && (
- <button
- className={`btn btn-link btn-animate ${
- this.state.my_vote.unwrapOr(0) == -1
- ? "text-danger"
- : "text-muted"
- }`}
- onClick={this.handleCommentDownvote}
- data-tippy-content={i18n.t("downvote")}
- aria-label={i18n.t("downvote")}
- >
- <Icon icon="arrow-down1" classes="icon-inline" />
- {showScores() &&
- this.state.upvotes !== this.state.score && (
- <span className="ml-1">
- {numToSI(this.state.downvotes)}
- </span>
- )}
- </button>
- )}
+ )}
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleReplyClick)}
+ data-tippy-content={i18n.t("reply")}
+ aria-label={i18n.t("reply")}
+ >
+ <Icon icon="reply1" classes="icon-inline" />
+ </button>
+ {!this.state.showAdvanced ? (
<button
className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(this, this.handleReplyClick)}
- data-tippy-content={i18n.t("reply")}
- aria-label={i18n.t("reply")}
+ onClick={linkEvent(this, this.handleShowAdvanced)}
+ data-tippy-content={i18n.t("more")}
+ aria-label={i18n.t("more")}
>
- <Icon icon="reply1" classes="icon-inline" />
+ <Icon icon="more-vertical" classes="icon-inline" />
</button>
- {!this.state.showAdvanced ? (
+ ) : (
+ <>
+ {!this.myComment && (
+ <>
+ <button className="btn btn-link btn-animate">
+ <Link
+ className="text-muted"
+ to={`/create_private_message/recipient/${cv.creator.id}`}
+ title={i18n.t("message").toLowerCase()}
+ >
+ <Icon icon="mail" />
+ </Link>
+ </button>
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleShowReportDialog
+ )}
+ data-tippy-content={i18n.t(
+ "show_report_dialog"
+ )}
+ aria-label={i18n.t("show_report_dialog")}
+ >
+ <Icon icon="flag" />
+ </button>
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleBlockUserClick
+ )}
+ data-tippy-content={i18n.t("block_user")}
+ aria-label={i18n.t("block_user")}
+ >
+ <Icon icon="slash" />
+ </button>
+ </>
+ )}
<button
className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(this, this.handleShowAdvanced)}
- data-tippy-content={i18n.t("more")}
- aria-label={i18n.t("more")}
+ onClick={linkEvent(
+ this,
+ this.handleSaveCommentClick
+ )}
+ data-tippy-content={
+ cv.saved ? i18n.t("unsave") : i18n.t("save")
+ }
+ aria-label={
+ cv.saved ? i18n.t("unsave") : i18n.t("save")
+ }
>
- <Icon icon="more-vertical" classes="icon-inline" />
+ {this.state.saveLoading ? (
+ this.loadingIcon
+ ) : (
+ <Icon
+ icon="star"
+ classes={`icon-inline ${
+ cv.saved && "text-warning"
+ }`}
+ />
+ )}
</button>
- ) : (
- <>
- {!this.myComment && (
- <>
- <button className="btn btn-link btn-animate">
- <Link
- className="text-muted"
- to={`/create_private_message/recipient/${cv.creator.id}`}
- title={i18n.t("message").toLowerCase()}
- >
- <Icon icon="mail" />
- </Link>
- </button>
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleShowReportDialog
- )}
- data-tippy-content={i18n.t(
- "show_report_dialog"
- )}
- aria-label={i18n.t("show_report_dialog")}
- >
- <Icon icon="flag" />
- </button>
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleViewSource)}
+ data-tippy-content={i18n.t("view_source")}
+ aria-label={i18n.t("view_source")}
+ >
+ <Icon
+ icon="file-text"
+ classes={`icon-inline ${
+ this.state.viewSource && "text-success"
+ }`}
+ />
+ </button>
+ {this.myComment && (
+ <>
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(this, this.handleEditClick)}
+ data-tippy-content={i18n.t("edit")}
+ aria-label={i18n.t("edit")}
+ >
+ <Icon icon="edit" classes="icon-inline" />
+ </button>
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleDeleteClick
+ )}
+ data-tippy-content={
+ !cv.comment.deleted
+ ? i18n.t("delete")
+ : i18n.t("restore")
+ }
+ aria-label={
+ !cv.comment.deleted
+ ? i18n.t("delete")
+ : i18n.t("restore")
+ }
+ >
+ <Icon
+ icon="trash"
+ classes={`icon-inline ${
+ cv.comment.deleted && "text-danger"
+ }`}
+ />
+ </button>
+
+ {(canModOnSelf || canAdminOnSelf) && (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleBlockUserClick
+ this.handleDistinguishClick
)}
- data-tippy-content={i18n.t("block_user")}
- aria-label={i18n.t("block_user")}
+ data-tippy-content={
+ !cv.comment.distinguished
+ ? i18n.t("distinguish")
+ : i18n.t("undistinguish")
+ }
+ aria-label={
+ !cv.comment.distinguished
+ ? i18n.t("distinguish")
+ : i18n.t("undistinguish")
+ }
>
- <Icon icon="slash" />
+ <Icon
+ icon="shield"
+ classes={`icon-inline ${
+ cv.comment.distinguished && "text-danger"
+ }`}
+ />
</button>
- </>
- )}
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleSaveCommentClick
- )}
- data-tippy-content={
- cv.saved ? i18n.t("unsave") : i18n.t("save")
- }
- aria-label={
- cv.saved ? i18n.t("unsave") : i18n.t("save")
- }
- >
- {this.state.saveLoading ? (
- this.loadingIcon
- ) : (
- <Icon
- icon="star"
- classes={`icon-inline ${
- cv.saved && "text-warning"
- }`}
- />
)}
- </button>
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(this, this.handleViewSource)}
- data-tippy-content={i18n.t("view_source")}
- aria-label={i18n.t("view_source")}
- >
- <Icon
- icon="file-text"
- classes={`icon-inline ${
- this.state.viewSource && "text-success"
- }`}
- />
- </button>
- {this.myComment && (
- <>
+ </>
+ )}
+ {/* Admins and mods can remove comments */}
+ {(canMod_ || canAdmin_) && (
+ <>
+ {!cv.comment.removed ? (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleEditClick
+ this.handleModRemoveShow
)}
- data-tippy-content={i18n.t("edit")}
- aria-label={i18n.t("edit")}
+ aria-label={i18n.t("remove")}
>
- <Icon icon="edit" classes="icon-inline" />
+ {i18n.t("remove")}
</button>
+ ) : (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleDeleteClick
+ this.handleModRemoveSubmit
)}
- data-tippy-content={
- !cv.comment.deleted
- ? i18n.t("delete")
- : i18n.t("restore")
- }
- aria-label={
- !cv.comment.deleted
- ? i18n.t("delete")
- : i18n.t("restore")
- }
+ aria-label={i18n.t("restore")}
>
- <Icon
- icon="trash"
- classes={`icon-inline ${
- cv.comment.deleted && "text-danger"
- }`}
- />
+ {i18n.t("restore")}
</button>
-
- {(canModOnSelf || canAdminOnSelf) && (
+ )}
+ </>
+ )}
+ {/* Mods can ban from community, and appoint as mods to community */}
+ {canMod_ && (
+ <>
+ {!isMod_ &&
+ (!cv.creator_banned_from_community ? (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleDistinguishClick
+ this.handleModBanFromCommunityShow
)}
- data-tippy-content={
- !cv.comment.distinguished
- ? i18n.t("distinguish")
- : i18n.t("undistinguish")
- }
- aria-label={
- !cv.comment.distinguished
- ? i18n.t("distinguish")
- : i18n.t("undistinguish")
- }
+ aria-label={i18n.t("ban")}
>
- <Icon
- icon="shield"
- classes={`icon-inline ${
- cv.comment.distinguished &&
- "text-danger"
- }`}
- />
+ {i18n.t("ban")}
</button>
- )}
- </>
- )}
- {/* Admins and mods can remove comments */}
- {(canMod_ || canAdmin_) && (
- <>
- {!cv.comment.removed ? (
+ ) : (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleModRemoveShow
+ this.handleModBanFromCommunitySubmit
)}
- aria-label={i18n.t("remove")}
+ aria-label={i18n.t("unban")}
>
- {i18n.t("remove")}
+ {i18n.t("unban")}
</button>
- ) : (
+ ))}
+ {!cv.creator_banned_from_community &&
+ (!this.state.showConfirmAppointAsMod ? (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleModRemoveSubmit
+ this.handleShowConfirmAppointAsMod
)}
- aria-label={i18n.t("restore")}
+ aria-label={
+ isMod_
+ ? i18n.t("remove_as_mod")
+ : i18n.t("appoint_as_mod")
+ }
>
- {i18n.t("restore")}
+ {isMod_
+ ? i18n.t("remove_as_mod")
+ : i18n.t("appoint_as_mod")}
</button>
- )}
- </>
- )}
- {/* Mods can ban from community, and appoint as mods to community */}
- {canMod_ && (
- <>
- {!isMod_ &&
- (!cv.creator_banned_from_community ? (
+ ) : (
+ <>
<button
className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleModBanFromCommunityShow
- )}
- aria-label={i18n.t("ban")}
+ aria-label={i18n.t("are_you_sure")}
>
- {i18n.t("ban")}
+ {i18n.t("are_you_sure")}
</button>
- ) : (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleModBanFromCommunitySubmit
+ this.handleAddModToCommunity
)}
- aria-label={i18n.t("unban")}
+ aria-label={i18n.t("yes")}
>
- {i18n.t("unban")}
+ {i18n.t("yes")}
</button>
- ))}
- {!cv.creator_banned_from_community &&
- (!this.state.showConfirmAppointAsMod ? (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleShowConfirmAppointAsMod
+ this.handleCancelConfirmAppointAsMod
)}
- aria-label={
- isMod_
- ? i18n.t("remove_as_mod")
- : i18n.t("appoint_as_mod")
- }
+ aria-label={i18n.t("no")}
>
- {isMod_
- ? i18n.t("remove_as_mod")
- : i18n.t("appoint_as_mod")}
+ {i18n.t("no")}
</button>
- ) : (
- <>
- <button
- className="btn btn-link btn-animate text-muted"
- aria-label={i18n.t("are_you_sure")}
- >
- {i18n.t("are_you_sure")}
- </button>
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleAddModToCommunity
- )}
- aria-label={i18n.t("yes")}
- >
- {i18n.t("yes")}
- </button>
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleCancelConfirmAppointAsMod
- )}
- aria-label={i18n.t("no")}
- >
- {i18n.t("no")}
- </button>
- </>
- ))}
- </>
- )}
- {/* 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 ? (
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleShowConfirmTransferCommunity
+ )}
+ aria-label={i18n.t("transfer_community")}
+ >
+ {i18n.t("transfer_community")}
+ </button>
+ ) : (
+ <>
+ <button
+ className="btn btn-link btn-animate text-muted"
+ aria-label={i18n.t("are_you_sure")}
+ >
+ {i18n.t("are_you_sure")}
+ </button>
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleShowConfirmTransferCommunity
+ this.handleTransferCommunity
)}
- aria-label={i18n.t("transfer_community")}
+ aria-label={i18n.t("yes")}
>
- {i18n.t("transfer_community")}
+ {i18n.t("yes")}
</button>
- ) : (
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this
+ .handleCancelShowConfirmTransferCommunity
+ )}
+ aria-label={i18n.t("no")}
+ >
+ {i18n.t("no")}
+ </button>
+ </>
+ ))}
+ {/* Admins can ban from all, and appoint other admins */}
+ {canAdmin_ && (
+ <>
+ {!isAdmin_ && (
<>
- <button
- className="btn btn-link btn-animate text-muted"
- aria-label={i18n.t("are_you_sure")}
- >
- {i18n.t("are_you_sure")}
- </button>
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleTransferCommunity
+ this.handlePurgePersonShow
)}
- aria-label={i18n.t("yes")}
+ aria-label={i18n.t("purge_user")}
>
- {i18n.t("yes")}
+ {i18n.t("purge_user")}
</button>
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this
- .handleCancelShowConfirmTransferCommunity
+ this.handlePurgeCommentShow
)}
- aria-label={i18n.t("no")}
+ aria-label={i18n.t("purge_comment")}
>
- {i18n.t("no")}
+ {i18n.t("purge_comment")}
</button>
- </>
- ))}
- {/* Admins can ban from all, and appoint other admins */}
- {canAdmin_ && (
- <>
- {!isAdmin_ && (
- <>
+
+ {!isBanned(cv.creator) ? (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handlePurgePersonShow
+ this.handleModBanShow
)}
- aria-label={i18n.t("purge_user")}
+ aria-label={i18n.t("ban_from_site")}
>
- {i18n.t("purge_user")}
+ {i18n.t("ban_from_site")}
</button>
+ ) : (
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handlePurgeCommentShow
+ this.handleModBanSubmit
)}
- aria-label={i18n.t("purge_comment")}
+ aria-label={i18n.t("unban_from_site")}
>
- {i18n.t("purge_comment")}
+ {i18n.t("unban_from_site")}
</button>
-
- {!isBanned(cv.creator) ? (
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleModBanShow
- )}
- aria-label={i18n.t("ban_from_site")}
- >
- {i18n.t("ban_from_site")}
- </button>
- ) : (
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleModBanSubmit
- )}
- aria-label={i18n.t("unban_from_site")}
- >
- {i18n.t("unban_from_site")}
- </button>
+ )}
+ </>
+ )}
+ {!isBanned(cv.creator) &&
+ cv.creator.local &&
+ (!this.state.showConfirmAppointAsAdmin ? (
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleShowConfirmAppointAsAdmin
)}
- </>
- )}
- {!isBanned(cv.creator) &&
- cv.creator.local &&
- (!this.state.showConfirmAppointAsAdmin ? (
+ aria-label={
+ isAdmin_
+ ? i18n.t("remove_as_admin")
+ : i18n.t("appoint_as_admin")
+ }
+ >
+ {isAdmin_
+ ? i18n.t("remove_as_admin")
+ : i18n.t("appoint_as_admin")}
+ </button>
+ ) : (
+ <>
+ <button className="btn btn-link btn-animate text-muted">
+ {i18n.t("are_you_sure")}
+ </button>
<button
className="btn btn-link btn-animate text-muted"
onClick={linkEvent(
this,
- this.handleShowConfirmAppointAsAdmin
+ this.handleAddAdmin
)}
- aria-label={
- isAdmin_
- ? i18n.t("remove_as_admin")
- : i18n.t("appoint_as_admin")
- }
+ aria-label={i18n.t("yes")}
>
- {isAdmin_
- ? i18n.t("remove_as_admin")
- : i18n.t("appoint_as_admin")}
+ {i18n.t("yes")}
</button>
- ) : (
- <>
- <button className="btn btn-link btn-animate text-muted">
- {i18n.t("are_you_sure")}
- </button>
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleAddAdmin
- )}
- aria-label={i18n.t("yes")}
- >
- {i18n.t("yes")}
- </button>
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={linkEvent(
- this,
- this.handleCancelConfirmAppointAsAdmin
- )}
- aria-label={i18n.t("no")}
- >
- {i18n.t("no")}
- </button>
- </>
- ))}
- </>
- )}
- </>
- )}
- </>
- )}
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={linkEvent(
+ this,
+ this.handleCancelConfirmAppointAsAdmin
+ )}
+ aria-label={i18n.t("no")}
+ >
+ {i18n.t("no")}
+ </button>
+ </>
+ ))}
+ </>
+ )}
+ </>
+ )}
+ </>
+ )}
</div>
{/* end of button group */}
</div>
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)}
/>
<button
id={`mod-ban-reason-${cv.comment.id}`}
className="form-control mr-2"
placeholder={i18n.t("reason")}
- value={toUndefined(this.state.banReason)}
+ value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
<label
id={`mod-ban-expires-${cv.comment.id}`}
className="form-control mr-2"
placeholder={i18n.t("number_of_days")}
- value={toUndefined(this.state.banExpireDays)}
+ value={this.state.banExpireDays}
onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
/>
<div className="form-group">
id="purge-reason"
className="form-control my-3"
placeholder={i18n.t("reason")}
- value={toUndefined(this.state.purgeReason)}
+ value={this.state.purgeReason}
onInput={linkEvent(this, this.handlePurgeReasonChange)}
/>
<div className="form-group row col-12">
)}
{this.state.showReply && (
<CommentForm
- node={Left(node)}
+ node={node}
onReplyCancel={this.handleReplyCancel}
disabled={this.props.locked}
focus
locked={this.props.locked}
moderators={this.props.moderators}
admins={this.props.admins}
- maxCommentsShown={None}
enableDownvotes={this.props.enableDownvotes}
viewType={this.props.viewType}
allLanguages={this.props.allLanguages}
}
get myComment(): boolean {
- return UserService.Instance.myUserInfo
- .map(
- m =>
- m.local_user_view.person.id == this.props.node.comment_view.creator.id
- )
- .unwrapOr(false);
+ return (
+ UserService.Instance.myUserInfo?.local_user_view.person.id ==
+ this.props.node.comment_view.creator.id
+ );
}
get isPostCreator(): boolean {
}
handleBlockUserClick(i: CommentNode) {
- let blockUserForm = new BlockPerson({
- person_id: i.props.node.comment_view.creator.id,
- block: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockUserForm: BlockPerson = {
+ person_id: i.props.node.comment_view.creator.id,
+ block: true,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
}
handleDeleteClick(i: CommentNode) {
let comment = i.props.node.comment_view.comment;
- let deleteForm = new DeleteComment({
- comment_id: comment.id,
- deleted: !comment.deleted,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.deleteComment(deleteForm));
+ let auth = myAuth();
+ if (auth) {
+ let deleteForm: DeleteComment = {
+ comment_id: comment.id,
+ deleted: !comment.deleted,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.deleteComment(deleteForm));
+ }
}
handleSaveCommentClick(i: CommentNode) {
let cv = i.props.node.comment_view;
let save = cv.saved == undefined ? true : !cv.saved;
- let form = new SaveComment({
- comment_id: cv.comment.id,
- save,
- auth: auth().unwrap(),
- });
+ let auth = myAuth();
+ if (auth) {
+ let form: SaveComment = {
+ comment_id: cv.comment.id,
+ save,
+ auth,
+ };
- WebSocketService.Instance.send(wsClient.saveComment(form));
+ WebSocketService.Instance.send(wsClient.saveComment(form));
- i.setState({ saveLoading: true });
+ i.setState({ saveLoading: true });
+ }
}
handleReplyCancel() {
handleCommentUpvote(event: any) {
event.preventDefault();
- let myVote = this.state.my_vote.unwrapOr(0);
+ let myVote = this.state.my_vote;
let newVote = myVote == 1 ? 0 : 1;
if (myVote == 1) {
});
}
- this.setState({ my_vote: Some(newVote) });
-
- let form = new CreateCommentLike({
- comment_id: this.props.node.comment_view.comment.id,
- score: newVote,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.likeComment(form));
- setupTippy();
+ this.setState({ my_vote: newVote });
+
+ let auth = myAuth();
+ if (auth) {
+ let form: CreateCommentLike = {
+ comment_id: this.props.node.comment_view.comment.id,
+ score: newVote,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.likeComment(form));
+ setupTippy();
+ }
}
handleCommentDownvote(event: any) {
event.preventDefault();
- let myVote = this.state.my_vote.unwrapOr(0);
+ let myVote = this.state.my_vote;
let newVote = myVote == -1 ? 0 : -1;
if (myVote == 1) {
});
}
- this.setState({ my_vote: Some(newVote) });
+ this.setState({ my_vote: newVote });
- let form = new CreateCommentLike({
- comment_id: this.props.node.comment_view.comment.id,
- score: newVote,
- auth: auth().unwrap(),
- });
+ let auth = myAuth();
+ if (auth) {
+ let form: CreateCommentLike = {
+ comment_id: this.props.node.comment_view.comment.id,
+ score: newVote,
+ auth,
+ };
- WebSocketService.Instance.send(wsClient.likeComment(form));
- setupTippy();
+ WebSocketService.Instance.send(wsClient.likeComment(form));
+ setupTippy();
+ }
}
handleShowReportDialog(i: CommentNode) {
handleReportSubmit(i: CommentNode) {
let comment = i.props.node.comment_view.comment;
- let form = new CreateCommentReport({
- comment_id: comment.id,
- reason: i.state.reportReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.createCommentReport(form));
-
- i.setState({ showReportDialog: false });
+ let reason = i.state.reportReason;
+ let auth = myAuth();
+ if (reason && auth) {
+ let form: CreateCommentReport = {
+ comment_id: comment.id,
+ reason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.createCommentReport(form));
+ i.setState({ showReportDialog: false });
+ }
}
handleModRemoveShow(i: CommentNode) {
}
handleModRemoveReasonChange(i: CommentNode, event: any) {
- i.setState({ removeReason: Some(event.target.value) });
+ i.setState({ removeReason: event.target.value });
}
handleModRemoveDataChange(i: CommentNode, event: any) {
handleModRemoveSubmit(i: CommentNode) {
let comment = i.props.node.comment_view.comment;
- let form = new RemoveComment({
- comment_id: comment.id,
- removed: !comment.removed,
- reason: i.state.removeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.removeComment(form));
-
- i.setState({ showRemoveDialog: false });
+ let auth = myAuth();
+ if (auth) {
+ let form: RemoveComment = {
+ comment_id: comment.id,
+ removed: !comment.removed,
+ reason: i.state.removeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.removeComment(form));
+
+ i.setState({ showRemoveDialog: false });
+ }
}
handleDistinguishClick(i: CommentNode) {
let comment = i.props.node.comment_view.comment;
- let form = new EditComment({
- comment_id: comment.id,
- form_id: None, // TODO not sure about this
- content: None,
- distinguished: Some(!comment.distinguished),
- language_id: Some(comment.language_id),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.editComment(form));
- i.setState(i.state);
+ let auth = myAuth();
+ if (auth) {
+ let form: EditComment = {
+ comment_id: comment.id,
+ distinguished: !comment.distinguished,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.editComment(form));
+ i.setState(i.state);
+ }
}
isPersonMentionType(
}
handleMarkRead(i: CommentNode) {
- if (i.isPersonMentionType(i.props.node.comment_view)) {
- let form = new MarkPersonMentionAsRead({
- person_mention_id: i.props.node.comment_view.person_mention.id,
- read: !i.props.node.comment_view.person_mention.read,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.markPersonMentionAsRead(form));
- } else if (i.isCommentReplyType(i.props.node.comment_view)) {
- let form = new MarkCommentReplyAsRead({
- comment_reply_id: i.props.node.comment_view.comment_reply.id,
- read: !i.props.node.comment_view.comment_reply.read,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.markCommentReplyAsRead(form));
- }
+ let auth = myAuth();
+ if (auth) {
+ if (i.isPersonMentionType(i.props.node.comment_view)) {
+ let form: MarkPersonMentionAsRead = {
+ person_mention_id: i.props.node.comment_view.person_mention.id,
+ read: !i.props.node.comment_view.person_mention.read,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.markPersonMentionAsRead(form));
+ } else if (i.isCommentReplyType(i.props.node.comment_view)) {
+ let form: MarkCommentReplyAsRead = {
+ comment_reply_id: i.props.node.comment_view.comment_reply.id,
+ read: !i.props.node.comment_view.comment_reply.read,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.markCommentReplyAsRead(form));
+ }
- i.setState({ readLoading: true });
+ i.setState({ readLoading: true });
+ }
}
handleModBanFromCommunityShow(i: CommentNode) {
}
handleModBanReasonChange(i: CommentNode, event: any) {
- i.setState({ banReason: Some(event.target.value) });
+ i.setState({ banReason: event.target.value });
}
handleModBanExpireDaysChange(i: CommentNode, event: any) {
- i.setState({ banExpireDays: Some(event.target.value) });
+ i.setState({ banExpireDays: event.target.value });
}
handleModBanFromCommunitySubmit(i: CommentNode) {
handleModBanBothSubmit(i: CommentNode) {
let cv = i.props.node.comment_view;
-
- if (i.state.banType == BanType.Community) {
- // If its an unban, restore all their data
- let ban = !cv.creator_banned_from_community;
- if (ban == false) {
- i.setState({ removeData: false });
- }
- let form = new BanFromCommunity({
- person_id: cv.creator.id,
- community_id: cv.community.id,
- ban,
- remove_data: Some(i.state.removeData),
- reason: i.state.banReason,
- expires: i.state.banExpireDays.map(futureDaysToUnixTime),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.banFromCommunity(form));
- } else {
- // If its an unban, restore all their data
- let ban = !cv.creator.banned;
- if (ban == false) {
- i.setState({ removeData: false });
+ let auth = myAuth();
+ if (auth) {
+ if (i.state.banType == BanType.Community) {
+ // If its an unban, restore all their data
+ let ban = !cv.creator_banned_from_community;
+ if (ban == false) {
+ i.setState({ removeData: false });
+ }
+ let form: BanFromCommunity = {
+ person_id: cv.creator.id,
+ community_id: cv.community.id,
+ ban,
+ remove_data: i.state.removeData,
+ reason: i.state.banReason,
+ expires: futureDaysToUnixTime(i.state.banExpireDays),
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.banFromCommunity(form));
+ } else {
+ // If its an unban, restore all their data
+ let ban = !cv.creator.banned;
+ if (ban == false) {
+ i.setState({ removeData: false });
+ }
+ let form: BanPerson = {
+ person_id: cv.creator.id,
+ ban,
+ remove_data: i.state.removeData,
+ reason: i.state.banReason,
+ expires: futureDaysToUnixTime(i.state.banExpireDays),
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.banPerson(form));
}
- let form = new BanPerson({
- person_id: cv.creator.id,
- ban,
- remove_data: Some(i.state.removeData),
- reason: i.state.banReason,
- expires: i.state.banExpireDays.map(futureDaysToUnixTime),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.banPerson(form));
- }
- i.setState({ showBanDialog: false });
+ i.setState({ showBanDialog: false });
+ }
}
handlePurgePersonShow(i: CommentNode) {
}
handlePurgeReasonChange(i: CommentNode, event: any) {
- i.setState({ purgeReason: Some(event.target.value) });
+ i.setState({ purgeReason: event.target.value });
}
handlePurgeSubmit(i: CommentNode, event: any) {
event.preventDefault();
+ let auth = myAuth();
+ if (auth) {
+ if (i.state.purgeType == PurgeType.Person) {
+ let form: PurgePerson = {
+ person_id: i.props.node.comment_view.creator.id,
+ reason: i.state.purgeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.purgePerson(form));
+ } else if (i.state.purgeType == PurgeType.Comment) {
+ let form: PurgeComment = {
+ comment_id: i.props.node.comment_view.comment.id,
+ reason: i.state.purgeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.purgeComment(form));
+ }
- if (i.state.purgeType == PurgeType.Person) {
- let form = new PurgePerson({
- person_id: i.props.node.comment_view.creator.id,
- reason: i.state.purgeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.purgePerson(form));
- } else if (i.state.purgeType == PurgeType.Comment) {
- let form = new PurgeComment({
- comment_id: i.props.node.comment_view.comment.id,
- reason: i.state.purgeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.purgeComment(form));
+ i.setState({ purgeLoading: true });
}
-
- i.setState({ purgeLoading: true });
}
handleShowConfirmAppointAsMod(i: CommentNode) {
handleAddModToCommunity(i: CommentNode) {
let cv = i.props.node.comment_view;
- let form = new AddModToCommunity({
- person_id: cv.creator.id,
- community_id: cv.community.id,
- added: !isMod(i.props.moderators, cv.creator.id),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.addModToCommunity(form));
- i.setState({ showConfirmAppointAsMod: false });
+ let auth = myAuth();
+ if (auth) {
+ let form: AddModToCommunity = {
+ person_id: cv.creator.id,
+ community_id: cv.community.id,
+ added: !isMod(cv.creator.id, i.props.moderators),
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.addModToCommunity(form));
+ i.setState({ showConfirmAppointAsMod: false });
+ }
}
handleShowConfirmAppointAsAdmin(i: CommentNode) {
}
handleAddAdmin(i: CommentNode) {
- let creatorId = i.props.node.comment_view.creator.id;
- let form = new AddAdmin({
- person_id: creatorId,
- added: !isAdmin(i.props.admins, creatorId),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.addAdmin(form));
- i.setState({ showConfirmAppointAsAdmin: false });
+ let auth = myAuth();
+ if (auth) {
+ let creatorId = i.props.node.comment_view.creator.id;
+ let form: AddAdmin = {
+ person_id: creatorId,
+ added: !isAdmin(creatorId, i.props.admins),
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.addAdmin(form));
+ i.setState({ showConfirmAppointAsAdmin: false });
+ }
}
handleShowConfirmTransferCommunity(i: CommentNode) {
handleTransferCommunity(i: CommentNode) {
let cv = i.props.node.comment_view;
- let form = new TransferCommunity({
- community_id: cv.community.id,
- person_id: cv.creator.id,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.transferCommunity(form));
- i.setState({ showConfirmTransferCommunity: false });
+ let auth = myAuth();
+ if (auth) {
+ let form: TransferCommunity = {
+ community_id: cv.community.id,
+ person_id: cv.creator.id,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.transferCommunity(form));
+ i.setState({ showConfirmTransferCommunity: false });
+ }
}
handleShowConfirmTransferSite(i: CommentNode) {
}
handleFetchChildren(i: CommentNode) {
- let form = new GetComments({
- post_id: Some(i.props.node.comment_view.post.id),
- parent_id: Some(i.props.node.comment_view.comment.id),
- max_depth: Some(commentTreeMaxDepth),
- page: None,
- sort: None,
- limit: Some(999),
- type_: Some(ListingType.All),
- community_name: None,
- community_id: None,
- saved_only: Some(false),
- auth: auth(false).ok(),
- });
+ let form: GetComments = {
+ post_id: i.props.node.comment_view.post.id,
+ parent_id: i.props.node.comment_view.comment.id,
+ max_depth: commentTreeMaxDepth,
+ limit: 999, // TODO
+ type_: ListingType.All,
+ saved_only: false,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(wsClient.getComments(form));
}
get scoreColor() {
- if (this.state.my_vote.unwrapOr(0) == 1) {
+ if (this.state.my_vote == 1) {
return "text-info";
- } else if (this.state.my_vote.unwrapOr(0) == -1) {
+ } else if (this.state.my_vote == -1) {
return "text-danger";
} else {
return "text-muted";
-import { Option } from "@sniptt/monads";
import { Component } from "inferno";
import {
CommentNode as CommentNodeI,
interface CommentNodesProps {
nodes: CommentNodeI[];
- moderators: Option<CommunityModeratorView[]>;
- admins: Option<PersonViewSafe[]>;
- maxCommentsShown: Option<number>;
+ moderators?: CommunityModeratorView[];
+ admins?: PersonViewSafe[];
+ maxCommentsShown?: number;
noBorder?: boolean;
noIndent?: boolean;
viewOnly?: boolean;
}
render() {
- let maxComments = this.props.maxCommentsShown.unwrapOr(
- this.props.nodes.length
- );
+ let maxComments = this.props.maxCommentsShown ?? this.props.nodes.length;
return (
<div className="comments">
-import { None } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
import { i18n } from "../../i18next";
import { CommentViewType } from "../../interfaces";
import { WebSocketService } from "../../services";
-import { auth, wsClient } from "../../utils";
+import { myAuth, wsClient } from "../../utils";
import { Icon } from "../common/icon";
import { PersonListing } from "../person/person-listing";
import { CommentNode } from "./comment-node";
<CommentNode
node={node}
viewType={CommentViewType.Flat}
- moderators={None}
- admins={None}
enableDownvotes={true}
viewOnly={true}
showCommunity={true}
<div>
{i18n.t("reason")}: {r.comment_report.reason}
</div>
- {r.resolver.match({
- some: resolver => (
- <div>
- {r.comment_report.resolved ? (
- <T i18nKey="resolved_by">
- #
- <PersonListing person={resolver} />
- </T>
- ) : (
- <T i18nKey="unresolved_by">
- #
- <PersonListing person={resolver} />
- </T>
- )}
- </div>
- ),
- none: <></>,
- })}
+ {r.resolver && (
+ <div>
+ {r.comment_report.resolved ? (
+ <T i18nKey="resolved_by">
+ #
+ <PersonListing person={r.resolver} />
+ </T>
+ ) : (
+ <T i18nKey="unresolved_by">
+ #
+ <PersonListing person={r.resolver} />
+ </T>
+ )}
+ </div>
+ )}
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleResolveReport)}
}
handleResolveReport(i: CommentReport) {
- let form = new ResolveCommentReport({
- report_id: i.props.report.comment_report.id,
- resolved: !i.props.report.comment_report.resolved,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.resolveCommentReport(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: ResolveCommentReport = {
+ report_id: i.props.report.comment_report.id,
+ resolved: !i.props.report.comment_report.resolved,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.resolveCommentReport(form));
+ }
}
}
-import { Option } from "@sniptt/monads";
import { Component } from "inferno";
import { PictrsImage } from "./pictrs-image";
interface BannerIconHeaderProps {
- banner: Option<string>;
- icon: Option<string>;
+ banner?: string;
+ icon?: string;
}
export class BannerIconHeader extends Component<BannerIconHeaderProps, any> {
}
render() {
+ let banner = this.props.banner;
+ let icon = this.props.icon;
return (
<div className="position-relative mb-2">
- {this.props.banner.match({
- some: banner => <PictrsImage src={banner} banner alt="" />,
- none: <></>,
- })}
- {this.props.icon.match({
- some: icon => (
- <PictrsImage
- src={icon}
- iconOverlay
- pushup={this.props.banner.isSome()}
- alt=""
- />
- ),
- none: <></>,
- })}
+ {banner && <PictrsImage src={banner} banner alt="" />}
+ {icon && (
+ <PictrsImage
+ src={icon}
+ iconOverlay
+ pushup={!!this.props.banner}
+ alt=""
+ />
+ )}
</div>
);
}
CommentSortSelectState
> {
private id = `sort-select-${randomStr()}`;
- private emptyState: CommentSortSelectState = {
+ state: CommentSortSelectState = {
sort: this.props.sort,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
static getDerivedStateFromProps(props: any): CommentSortSelectState {
}
handleSortChange(i: CommentSortSelect, event: any) {
- i.props.onChange(event.target.value);
+ i.props.onChange?.(event.target.value);
}
}
DataTypeSelectProps,
DataTypeSelectState
> {
- private emptyState: DataTypeSelectState = {
+ state: DataTypeSelectState = {
type_: this.props.type_,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
static getDerivedStateFromProps(props: any): DataTypeSelectProps {
}
handleTypeChange(i: DataTypeSelect, event: any) {
- i.props.onChange(Number(event.target.value));
+ i.props.onChange?.(Number(event.target.value));
}
}
-import { Option } from "@sniptt/monads";
import { htmlToText } from "html-to-text";
import { Component } from "inferno";
import { Helmet } from "inferno-helmet";
interface HtmlTagsProps {
title: string;
path: string;
- description: Option<string>;
- image: Option<string>;
+ description?: string;
+ image?: string;
}
/// Taken from https://metatags.io/
export class HtmlTags extends Component<HtmlTagsProps, any> {
render() {
let url = httpExternalPath(this.props.path);
+ let desc = this.props.description;
+ let image = this.props.image;
return (
<Helmet title={this.props.title}>
<meta property="twitter:card" content="summary_large_image" />
{/* Optional desc and images */}
- {this.props.description.isSome() &&
- ["description", "og:description", "twitter:description"].map(n => (
- <meta
- key={n}
- name={n}
- content={htmlToText(
- md.renderInline(this.props.description.unwrap())
- )}
- />
- ))}
-
- {this.props.image.isSome() &&
- ["og:image", "twitter:image"].map(p => (
- <meta key={p} property={p} content={this.props.image.unwrap()} />
- ))}
+ {["description", "og:description", "twitter:description"].map(
+ n =>
+ desc && (
+ <meta
+ key={n}
+ name={n}
+ content={htmlToText(md.renderInline(desc))}
+ />
+ )
+ )}
+ {["og:image", "twitter:image"].map(
+ p => image && <meta key={p} property={p} content={image} />
+ )}
</Helmet>
);
}
-import { Option } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { pictrsUri } from "../../env";
import { i18n } from "../../i18next";
interface ImageUploadFormProps {
uploadTitle: string;
- imageSrc: Option<string>;
+ imageSrc?: string;
onUpload(url: string): any;
onRemove(): any;
rounded?: boolean;
htmlFor={this.id}
className="pointer text-muted small font-weight-bold"
>
- {this.props.imageSrc.match({
- some: imageSrc => (
- <span className="d-inline-block position-relative">
- <img
- src={imageSrc}
- height={this.props.rounded ? 60 : ""}
- width={this.props.rounded ? 60 : ""}
- className={`img-fluid ${
- this.props.rounded ? "rounded-circle" : ""
- }`}
- />
- <a
- onClick={linkEvent(this, this.handleRemoveImage)}
- aria-label={i18n.t("remove")}
- >
- <Icon icon="x" classes="mini-overlay" />
- </a>
- </span>
- ),
- none: (
- <span className="btn btn-secondary">
- {this.props.uploadTitle}
- </span>
- ),
- })}
+ {this.props.imageSrc ? (
+ <span className="d-inline-block position-relative">
+ <img
+ src={this.props.imageSrc}
+ height={this.props.rounded ? 60 : ""}
+ width={this.props.rounded ? 60 : ""}
+ className={`img-fluid ${
+ this.props.rounded ? "rounded-circle" : ""
+ }`}
+ />
+ <a
+ onClick={linkEvent(this, this.handleRemoveImage)}
+ aria-label={i18n.t("remove")}
+ >
+ <Icon icon="x" classes="mini-overlay" />
+ </a>
+ </span>
+ ) : (
+ <span className="btn btn-secondary">{this.props.uploadTitle}</span>
+ )}
</label>
<input
id={this.id}
accept="image/*,video/*"
name={this.id}
className="d-none"
- disabled={UserService.Instance.myUserInfo.isNone()}
+ disabled={!UserService.Instance.myUserInfo}
onChange={linkEvent(this, this.handleImageUpload)}
/>
</form>
-import { Option } from "@sniptt/monads";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import { Language } from "lemmy-js-client";
interface LanguageSelectProps {
allLanguages: Language[];
siteLanguages: number[];
- selectedLanguageIds: Option<number[]>;
+ selectedLanguageIds?: number[];
multiple: boolean;
onChange(val: number[]): any;
showAll?: boolean;
// Necessary because there is no HTML way to set selected for multiple in value=
setSelectedValues() {
- this.props.selectedLanguageIds.map(toString).match({
- some: ids => {
- var select = (document.getElementById(this.id) as HTMLSelectElement)
- .options;
- for (let i = 0; i < select.length; i++) {
- let o = select[i];
- if (ids.includes(o.value)) {
- o.selected = true;
- }
+ let ids = this.props.selectedLanguageIds?.map(toString);
+ if (ids) {
+ let select = (document.getElementById(this.id) as HTMLSelectElement)
+ .options;
+ for (let i = 0; i < select.length; i++) {
+ let o = select[i];
+ if (ids.includes(o.value)) {
+ o.selected = true;
}
- },
- none: void 0,
- });
+ }
+ }
}
render() {
<option
key={l.id}
value={l.id}
- selected={selectedLangs.unwrapOr([]).includes(l.id)}
+ selected={selectedLangs?.includes(l.id)}
>
{l.name}
</option>
> {
private id = `listing-type-input-${randomStr()}`;
- private emptyState: ListingTypeSelectState = {
+ state: ListingTypeSelectState = {
type_: this.props.type_,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
static getDerivedStateFromProps(props: any): ListingTypeSelectProps {
title={i18n.t("subscribed_description")}
className={`btn btn-outline-secondary
${this.state.type_ == ListingType.Subscribed && "active"}
- ${UserService.Instance.myUserInfo.isNone() ? "disabled" : "pointer"}
+ ${!UserService.Instance.myUserInfo ? "disabled" : "pointer"}
`}
>
<input
value={ListingType.Subscribed}
checked={this.state.type_ == ListingType.Subscribed}
onChange={linkEvent(this, this.handleTypeChange)}
- disabled={UserService.Instance.myUserInfo.isNone()}
+ disabled={!UserService.Instance.myUserInfo}
/>
{i18n.t("subscribed")}
</label>
}
handleTypeChange(i: ListingTypeSelect, event: any) {
- i.props.onChange(event.target.value);
+ i.props.onChange?.(event.target.value);
}
}
-import { None, Option, Some } from "@sniptt/monads";
import autosize from "autosize";
import { Component, linkEvent } from "inferno";
import { Prompt } from "inferno-router";
-import { Language, toUndefined } from "lemmy-js-client";
+import { Language } from "lemmy-js-client";
import { pictrsUri } from "../../env";
import { i18n } from "../../i18next";
import { UserService } from "../../services";
import { LanguageSelect } from "./language-select";
interface MarkdownTextAreaProps {
- initialContent: Option<string>;
- initialLanguageId: Option<number>;
- placeholder: Option<string>;
- buttonTitle: Option<string>;
- maxLength: Option<number>;
+ initialContent?: string;
+ initialLanguageId?: number;
+ placeholder?: string;
+ buttonTitle?: string;
+ maxLength?: number;
replyType?: boolean;
focus?: boolean;
disabled?: boolean;
hideNavigationWarnings?: boolean;
onContentChange?(val: string): any;
onReplyCancel?(): any;
- onSubmit?(msg: {
- val: Option<string>;
- formId: string;
- languageId: Option<number>;
- }): any;
- allLanguages: Language[];
- siteLanguages: number[];
+ onSubmit?(msg: { val?: string; formId: string; languageId?: number }): any;
+ allLanguages: Language[]; // TODO should probably be nullable
+ siteLanguages: number[]; // TODO same
}
interface MarkdownTextAreaState {
- content: Option<string>;
- languageId: Option<number>;
+ content?: string;
+ languageId?: number;
previewMode: boolean;
loading: boolean;
imageLoading: boolean;
private id = `comment-textarea-${randomStr()}`;
private formId = `comment-form-${randomStr()}`;
private tribute: any;
- private emptyState: MarkdownTextAreaState = {
+ state: MarkdownTextAreaState = {
content: this.props.initialContent,
languageId: this.props.initialLanguageId,
previewMode: false,
if (isBrowser()) {
this.tribute = setupTribute();
}
- this.state = this.emptyState;
}
componentDidMount() {
autosize(textarea);
this.tribute.attach(textarea);
textarea.addEventListener("tribute-replaced", () => {
- this.setState({ content: Some(textarea.value) });
+ this.setState({ content: textarea.value });
autosize.update(textarea);
});
}
componentDidUpdate() {
- if (!this.props.hideNavigationWarnings && this.state.content.isSome()) {
+ if (!this.props.hideNavigationWarnings && this.state.content) {
window.onbeforeunload = () => true;
} else {
- window.onbeforeunload = undefined;
+ window.onbeforeunload = null;
}
}
componentWillReceiveProps(nextProps: MarkdownTextAreaProps) {
if (nextProps.finished) {
- this.setState({ previewMode: false, loading: false, content: None });
+ this.setState({ previewMode: false, loading: false, content: undefined });
if (this.props.replyType) {
- this.props.onReplyCancel();
+ this.props.onReplyCancel?.();
}
let textarea: any = document.getElementById(this.id);
}
render() {
+ let languageId = this.state.languageId;
+
return (
<form id={this.formId} onSubmit={linkEvent(this, this.handleSubmit)}>
<Prompt
- when={
- !this.props.hideNavigationWarnings && this.state.content.isSome()
- }
+ when={!this.props.hideNavigationWarnings && this.state.content}
message={i18n.t("block_leaving")}
/>
<div className="form-group row">
<textarea
id={this.id}
className={`form-control ${this.state.previewMode && "d-none"}`}
- value={toUndefined(this.state.content)}
+ value={this.state.content}
onInput={linkEvent(this, this.handleContentChange)}
onPaste={linkEvent(this, this.handleImageUploadPaste)}
required
disabled={this.props.disabled}
rows={2}
- maxLength={this.props.maxLength.unwrapOr(
- markdownFieldCharacterLimit
- )}
- placeholder={toUndefined(this.props.placeholder)}
+ maxLength={this.props.maxLength ?? markdownFieldCharacterLimit}
+ placeholder={this.props.placeholder}
/>
- {this.state.previewMode &&
- this.state.content.match({
- some: content => (
- <div
- className="card border-secondary card-body md-div"
- dangerouslySetInnerHTML={mdToHtml(content)}
- />
- ),
- none: <></>,
- })}
+ {this.state.previewMode && this.state.content && (
+ <div
+ className="card border-secondary card-body md-div"
+ dangerouslySetInnerHTML={mdToHtml(this.state.content)}
+ />
+ )}
</div>
<label className="sr-only" htmlFor={this.id}>
{i18n.t("body")}
</div>
<div className="row">
<div className="col-sm-12 d-flex flex-wrap">
- {this.props.buttonTitle.match({
- some: buttonTitle => (
- <button
- type="submit"
- className="btn btn-sm btn-secondary mr-2"
- disabled={this.props.disabled || this.state.loading}
- >
- {this.state.loading ? (
- <Spinner />
- ) : (
- <span>{buttonTitle}</span>
- )}
- </button>
- ),
- none: <></>,
- })}
+ {this.props.buttonTitle && (
+ <button
+ type="submit"
+ className="btn btn-sm btn-secondary mr-2"
+ disabled={this.props.disabled || this.state.loading}
+ >
+ {this.state.loading ? (
+ <Spinner />
+ ) : (
+ <span>{this.props.buttonTitle}</span>
+ )}
+ </button>
+ )}
{this.props.replyType && (
<button
type="button"
{i18n.t("cancel")}
</button>
)}
- {this.state.content.isSome() && (
+ {this.state.content && (
<button
className={`btn btn-sm btn-secondary mr-2 ${
this.state.previewMode && "active"
<LanguageSelect
iconVersion
allLanguages={this.props.allLanguages}
- selectedLanguageIds={this.state.languageId.map(Array.of)}
+ selectedLanguageIds={
+ languageId ? Array.of(languageId) : undefined
+ }
siteLanguages={this.props.siteLanguages}
multiple={false}
onChange={this.handleLanguageChange}
<label
htmlFor={`file-upload-${this.id}`}
className={`mb-0 ${
- UserService.Instance.myUserInfo.isSome() && "pointer"
+ UserService.Instance.myUserInfo && "pointer"
}`}
data-tippy-content={i18n.t("upload_image")}
>
accept="image/*,video/*"
name="file"
className="d-none"
- disabled={UserService.Instance.myUserInfo.isNone()}
+ disabled={!UserService.Instance.myUserInfo}
onChange={linkEvent(this, this.handleImageUpload)}
/>
</form>
let deleteToken = res.files[0].delete_token;
let deleteUrl = `${pictrsUri}/delete/${deleteToken}/${hash}`;
let imageMarkdown = `![](${url})`;
+ let content = i.state.content;
i.setState({
- content: Some(
- i.state.content.match({
- some: content => `${content}\n${imageMarkdown}`,
- none: imageMarkdown,
- })
- ),
+ content: content ? `${content}\n${imageMarkdown}` : imageMarkdown,
imageLoading: false,
});
i.contentChange();
}
contentChange() {
- if (this.props.onContentChange) {
- this.props.onContentChange(toUndefined(this.state.content));
+ if (this.state.content) {
+ this.props.onContentChange?.(this.state.content);
}
}
handleContentChange(i: MarkdownTextArea, event: any) {
- i.setState({ content: Some(event.target.value) });
+ i.setState({ content: event.target.value });
i.contentChange();
}
}
handleLanguageChange(val: number[]) {
- this.setState({ languageId: Some(val[0]) });
+ this.setState({ languageId: val[0] });
}
handleSubmit(i: MarkdownTextArea, event: any) {
formId: i.formId,
languageId: i.state.languageId,
};
- i.props.onSubmit(msg);
+ i.props.onSubmit?.(msg);
}
handleReplyCancel(i: MarkdownTextArea) {
- i.props.onReplyCancel();
+ i.props.onReplyCancel?.();
}
handleInsertLink(i: MarkdownTextArea, event: any) {
let start: number = textarea.selectionStart;
let end: number = textarea.selectionEnd;
- if (i.state.content.isNone()) {
- i.setState({ content: Some("") });
- }
+ let content = i.state.content;
- let content = i.state.content.unwrap();
+ if (!i.state.content) {
+ i.setState({ content: "" });
+ }
if (start !== end) {
- let selectedText = content.substring(start, end);
+ let selectedText = content?.substring(start, end);
i.setState({
- content: Some(
- `${content.substring(0, start)}[${selectedText}]()${content.substring(
- end
- )}`
- ),
+ content: `${content?.substring(
+ 0,
+ start
+ )}[${selectedText}]()${content?.substring(end)}`,
});
textarea.focus();
setTimeout(() => (textarea.selectionEnd = end + 3), 10);
} else {
- i.setState({ content: Some(`${content} []()`) });
+ i.setState({ content: `${content} []()` });
textarea.focus();
setTimeout(() => (textarea.selectionEnd -= 1), 10);
}
afterChars: string,
emptyChars = "___"
) {
- if (this.state.content.isNone()) {
- this.setState({ content: Some("") });
+ let content = this.state.content;
+ if (!this.state.content) {
+ this.setState({ content: "" });
}
let textarea: any = document.getElementById(this.id);
let start: number = textarea.selectionStart;
let end: number = textarea.selectionEnd;
- let content = this.state.content.unwrap();
-
if (start !== end) {
- let selectedText = content.substring(start, end);
+ let selectedText = content?.substring(start, end);
this.setState({
- content: Some(
- `${content.substring(
- 0,
- start
- )}${beforeChars}${selectedText}${afterChars}${content.substring(end)}`
- ),
+ content: `${content?.substring(
+ 0,
+ start
+ )}${beforeChars}${selectedText}${afterChars}${content?.substring(end)}`,
});
} else {
this.setState({
- content: Some(`${content}${beforeChars}${emptyChars}${afterChars}`),
+ content: `${content}${beforeChars}${emptyChars}${afterChars}`,
});
}
this.contentChange();
}
simpleInsert(chars: string) {
- if (this.state.content.isNone()) {
- this.setState({ content: Some(`${chars} `) });
+ let content = this.state.content;
+ if (!content) {
+ this.setState({ content: `${chars} ` });
} else {
this.setState({
- content: Some(`${this.state.content.unwrap()}\n${chars} `),
+ content: `${content}\n${chars} `,
});
}
quoteInsert() {
let textarea: any = document.getElementById(this.id);
- let selectedText = window.getSelection().toString();
+ let selectedText = window.getSelection()?.toString();
+ let content = this.state.content;
if (selectedText) {
let quotedText =
selectedText
.split("\n")
.map(t => `> ${t}`)
.join("\n") + "\n\n";
- if (this.state.content.isNone()) {
- this.setState({ content: Some("") });
+ if (!content) {
+ this.setState({ content: "" });
} else {
- this.setState({ content: Some(`${this.state.content.unwrap()}\n`) });
+ this.setState({ content: `${content}\n` });
}
this.setState({
- content: Some(`${this.state.content.unwrap()}${quotedText}`),
+ content: `${content}${quotedText}`,
});
this.contentChange();
// Not sure why this needs a delay
let textarea: any = document.getElementById(this.id);
let start: number = textarea.selectionStart;
let end: number = textarea.selectionEnd;
- return start !== end
- ? this.state.content.unwrap().substring(start, end)
- : "";
+ return start !== end ? this.state.content?.substring(start, end) ?? "" : "";
}
}
-import { Option } from "@sniptt/monads";
import { Component } from "inferno";
import moment from "moment";
import { i18n } from "../../i18next";
interface MomentTimeProps {
published: string;
- updated: Option<string>;
+ updated?: string;
showAgo?: boolean;
ignoreUpdated?: boolean;
}
}
createdAndModifiedTimes() {
- return `${capitalizeFirstLetter(i18n.t("created"))}: ${this.format(
+ let updated = this.props.updated;
+ let line = `${capitalizeFirstLetter(i18n.t("created"))}: ${this.format(
this.props.published
- )}\n\n\n${
- this.props.updated.isSome() && capitalizeFirstLetter(i18n.t("modified"))
- } ${this.format(this.props.updated.unwrap())}`;
+ )}`;
+ if (updated) {
+ line += `\n\n\n${capitalizeFirstLetter(i18n.t("modified"))} ${this.format(
+ updated
+ )}`;
+ }
+ return line;
}
render() {
- if (!this.props.ignoreUpdated && this.props.updated.isSome()) {
+ if (!this.props.ignoreUpdated && this.props.updated) {
return (
<span
data-tippy-content={this.createdAndModifiedTimes()}
className="font-italics pointer unselectable"
>
<Icon icon="edit-2" classes="icon-inline mr-1" />
- {moment.utc(this.props.updated.unwrap()).fromNow(!this.props.showAgo)}
+ {moment.utc(this.props.updated).fromNow(!this.props.showAgo)}
</span>
);
} else {
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
-import { auth, mdToHtml, wsClient } from "../../utils";
+import { mdToHtml, myAuth, wsClient } from "../../utils";
import { PersonListing } from "../person/person-listing";
import { MarkdownTextArea } from "./markdown-textarea";
import { MomentTime } from "./moment-time";
}
interface RegistrationApplicationState {
- denyReason: Option<string>;
+ denyReason?: string;
denyExpanded: boolean;
}
RegistrationApplicationProps,
RegistrationApplicationState
> {
- private emptyState: RegistrationApplicationState = {
+ state: RegistrationApplicationState = {
denyReason: this.props.application.registration_application.deny_reason,
denyExpanded: false,
};
constructor(props: any, context: any) {
super(props, context);
-
- this.state = this.emptyState;
this.handleDenyReasonChange = this.handleDenyReasonChange.bind(this);
}
{i18n.t("applicant")}: <PersonListing person={a.creator} />
</div>
<div>
- {i18n.t("created")}:{" "}
- <MomentTime showAgo published={ra.published} updated={None} />
+ {i18n.t("created")}: <MomentTime showAgo published={ra.published} />
</div>
<div>{i18n.t("answer")}:</div>
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(ra.answer)} />
- {a.admin.match({
- some: admin => (
- <div>
- {accepted ? (
- <T i18nKey="approved_by">
+ {a.admin && (
+ <div>
+ {accepted ? (
+ <T i18nKey="approved_by">
+ #
+ <PersonListing person={a.admin} />
+ </T>
+ ) : (
+ <div>
+ <T i18nKey="denied_by">
#
- <PersonListing person={admin} />
+ <PersonListing person={a.admin} />
</T>
- ) : (
- <div>
- <T i18nKey="denied_by">
- #
- <PersonListing person={admin} />
- </T>
- {ra.deny_reason.match({
- some: deny_reason => (
- <div>
- {i18n.t("deny_reason")}:{" "}
- <div
- className="md-div d-inline-flex"
- dangerouslySetInnerHTML={mdToHtml(deny_reason)}
- />
- </div>
- ),
- none: <></>,
- })}
- </div>
- )}
- </div>
- ),
- none: <></>,
- })}
+ {ra.deny_reason && (
+ <div>
+ {i18n.t("deny_reason")}:{" "}
+ <div
+ className="md-div d-inline-flex"
+ dangerouslySetInnerHTML={mdToHtml(ra.deny_reason)}
+ />
+ </div>
+ )}
+ </div>
+ )}
+ </div>
+ )}
{this.state.denyExpanded && (
<div className="form-group row">
<div className="col-sm-10">
<MarkdownTextArea
initialContent={this.state.denyReason}
- initialLanguageId={None}
onContentChange={this.handleDenyReasonChange}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
hideNavigationWarnings
allLanguages={[]}
siteLanguages={[]}
</div>
</div>
)}
- {(ra.admin_id.isNone() || (ra.admin_id.isSome() && !accepted)) && (
+ {(!ra.admin_id || (ra.admin_id && !accepted)) && (
<button
className="btn btn-secondary mr-2 my-2"
onClick={linkEvent(this, this.handleApprove)}
{i18n.t("approve")}
</button>
)}
- {(ra.admin_id.isNone() || (ra.admin_id.isSome() && accepted)) && (
+ {(!ra.admin_id || (ra.admin_id && accepted)) && (
<button
className="btn btn-secondary mr-2"
onClick={linkEvent(this, this.handleDeny)}
}
handleApprove(i: RegistrationApplication) {
- i.setState({ denyExpanded: false });
- let form = new ApproveRegistrationApplication({
- id: i.props.application.registration_application.id,
- deny_reason: None,
- approve: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(
- wsClient.approveRegistrationApplication(form)
- );
- }
-
- handleDeny(i: RegistrationApplication) {
- if (i.state.denyExpanded) {
+ let auth = myAuth();
+ if (auth) {
i.setState({ denyExpanded: false });
- let form = new ApproveRegistrationApplication({
+ let form: ApproveRegistrationApplication = {
id: i.props.application.registration_application.id,
- approve: false,
- deny_reason: i.state.denyReason,
- auth: auth().unwrap(),
- });
+ approve: true,
+ auth,
+ };
WebSocketService.Instance.send(
wsClient.approveRegistrationApplication(form)
);
+ }
+ }
+
+ handleDeny(i: RegistrationApplication) {
+ if (i.state.denyExpanded) {
+ i.setState({ denyExpanded: false });
+ let auth = myAuth();
+ if (auth) {
+ let form: ApproveRegistrationApplication = {
+ id: i.props.application.registration_application.id,
+ approve: false,
+ deny_reason: i.state.denyReason,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.approveRegistrationApplication(form)
+ );
+ }
} else {
i.setState({ denyExpanded: true });
}
}
handleDenyReasonChange(val: string) {
- this.setState({ denyReason: Some(val) });
+ this.setState({ denyReason: val });
}
}
export class SortSelect extends Component<SortSelectProps, SortSelectState> {
private id = `sort-select-${randomStr()}`;
- private emptyState: SortSelectState = {
+ state: SortSelectState = {
sort: this.props.sort,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
static getDerivedStateFromProps(props: any): SortSelectState {
}
handleSortChange(i: SortSelect, event: any) {
- i.props.onChange(event.target.value);
+ i.props.onChange?.(event.target.value);
}
}
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
CommunityResponse,
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
import {
- auth,
getListingTypeFromPropsNoDefault,
getPageFromProps,
isBrowser,
+ myAuth,
numToSI,
setIsoData,
showLocal,
const communityLimit = 50;
interface CommunitiesState {
- listCommunitiesResponse: Option<ListCommunitiesResponse>;
+ listCommunitiesResponse?: ListCommunitiesResponse;
page: number;
loading: boolean;
siteRes: GetSiteResponse;
}
export class Communities extends Component<any, CommunitiesState> {
- private subscription: Subscription;
- private isoData = setIsoData(this.context, ListCommunitiesResponse);
- private emptyState: CommunitiesState = {
- listCommunitiesResponse: None,
+ private subscription?: Subscription;
+ private isoData = setIsoData(this.context);
+ state: CommunitiesState = {
loading: true,
page: getPageFromProps(this.props),
listingType: getListingTypeFromPropsNoDefault(this.props),
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePageChange = this.handlePageChange.bind(this);
this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
- let listRes = Some(this.isoData.routeData[0] as ListCommunitiesResponse);
+ let listRes = this.isoData.routeData[0] as ListCommunitiesResponse;
this.state = {
...this.state,
listCommunitiesResponse: listRes,
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
{this.state.loading ? (
<h5>
</tr>
</thead>
<tbody>
- {this.state.listCommunitiesResponse
- .map(l => l.communities)
- .unwrapOr([])
- .map(cv => (
- <tr key={cv.community.id}>
- <td>
- <CommunityLink community={cv.community} />
- </td>
- <td className="text-right">
- {numToSI(cv.counts.subscribers)}
- </td>
- <td className="text-right">
- {numToSI(cv.counts.users_active_month)}
- </td>
- <td className="text-right d-none d-lg-table-cell">
- {numToSI(cv.counts.posts)}
- </td>
- <td className="text-right d-none d-lg-table-cell">
- {numToSI(cv.counts.comments)}
- </td>
- <td className="text-right">
- {cv.subscribed == SubscribedType.Subscribed && (
- <button
- className="btn btn-link d-inline-block"
- onClick={linkEvent(
- cv.community.id,
- this.handleUnsubscribe
- )}
- >
- {i18n.t("unsubscribe")}
- </button>
- )}
- {cv.subscribed == SubscribedType.NotSubscribed && (
- <button
- className="btn btn-link d-inline-block"
- onClick={linkEvent(
- cv.community.id,
- this.handleSubscribe
- )}
- >
- {i18n.t("subscribe")}
- </button>
- )}
- {cv.subscribed == SubscribedType.Pending && (
- <div className="text-warning d-inline-block">
- {i18n.t("subscribe_pending")}
- </div>
- )}
- </td>
- </tr>
- ))}
+ {this.state.listCommunitiesResponse?.communities.map(cv => (
+ <tr key={cv.community.id}>
+ <td>
+ <CommunityLink community={cv.community} />
+ </td>
+ <td className="text-right">
+ {numToSI(cv.counts.subscribers)}
+ </td>
+ <td className="text-right">
+ {numToSI(cv.counts.users_active_month)}
+ </td>
+ <td className="text-right d-none d-lg-table-cell">
+ {numToSI(cv.counts.posts)}
+ </td>
+ <td className="text-right d-none d-lg-table-cell">
+ {numToSI(cv.counts.comments)}
+ </td>
+ <td className="text-right">
+ {cv.subscribed == SubscribedType.Subscribed && (
+ <button
+ className="btn btn-link d-inline-block"
+ onClick={linkEvent(
+ cv.community.id,
+ this.handleUnsubscribe
+ )}
+ >
+ {i18n.t("unsubscribe")}
+ </button>
+ )}
+ {cv.subscribed == SubscribedType.NotSubscribed && (
+ <button
+ className="btn btn-link d-inline-block"
+ onClick={linkEvent(
+ cv.community.id,
+ this.handleSubscribe
+ )}
+ >
+ {i18n.t("subscribe")}
+ </button>
+ )}
+ {cv.subscribed == SubscribedType.Pending && (
+ <div className="text-warning d-inline-block">
+ {i18n.t("subscribe_pending")}
+ </div>
+ )}
+ </td>
+ </tr>
+ ))}
</tbody>
</table>
</div>
}
handleUnsubscribe(communityId: number) {
- let form = new FollowCommunity({
- community_id: communityId,
- follow: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.followCommunity(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: FollowCommunity = {
+ community_id: communityId,
+ follow: false,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
+ }
}
handleSubscribe(communityId: number) {
- let form = new FollowCommunity({
- community_id: communityId,
- follow: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.followCommunity(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: FollowCommunity = {
+ community_id: communityId,
+ follow: true,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
+ }
}
handleSearchChange(i: Communities, event: any) {
}
refetch() {
- let listCommunitiesForm = new ListCommunities({
- type_: Some(this.state.listingType),
- sort: Some(SortType.TopMonth),
- limit: Some(communityLimit),
- page: Some(this.state.page),
- auth: auth(false).ok(),
- });
+ let listCommunitiesForm: ListCommunities = {
+ type_: this.state.listingType,
+ sort: SortType.TopMonth,
+ limit: communityLimit,
+ page: this.state.page,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(
wsClient.listCommunities(listCommunitiesForm)
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split("/");
- let type_: Option<ListingType> = Some(
- pathSplit[3] ? ListingType[pathSplit[3]] : ListingType.Local
- );
- let page = Some(pathSplit[5] ? Number(pathSplit[5]) : 1);
- let listCommunitiesForm = new ListCommunities({
+ let type_: ListingType = pathSplit[3]
+ ? ListingType[pathSplit[3]]
+ : ListingType.Local;
+ let page = pathSplit[5] ? Number(pathSplit[5]) : 1;
+ let listCommunitiesForm: ListCommunities = {
type_,
- sort: Some(SortType.TopMonth),
- limit: Some(communityLimit),
+ sort: SortType.TopMonth,
+ limit: communityLimit,
page,
auth: req.auth,
- });
+ };
return [req.client.listCommunities(listCommunitiesForm)];
}
toast(i18n.t(msg.error), "danger");
return;
} else if (op == UserOperation.ListCommunities) {
- let data = wsJsonToRes<ListCommunitiesResponse>(
- msg,
- ListCommunitiesResponse
- );
- this.setState({ listCommunitiesResponse: Some(data), loading: false });
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg);
+ this.setState({ listCommunitiesResponse: data, loading: false });
window.scrollTo(0, 0);
} else if (op == UserOperation.FollowCommunity) {
- let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
- this.state.listCommunitiesResponse.match({
- some: res => {
- let found = res.communities.find(
- c => c.community.id == data.community_view.community.id
- );
- found.subscribed = data.community_view.subscribed;
- found.counts.subscribers = data.community_view.counts.subscribers;
- },
- none: void 0,
- });
- this.setState(this.state);
+ let data = wsJsonToRes<CommunityResponse>(msg);
+ let res = this.state.listCommunitiesResponse;
+ let found = res?.communities.find(
+ c => c.community.id == data.community_view.community.id
+ );
+ if (found) {
+ found.subscribed = data.community_view.subscribed;
+ found.counts.subscribers = data.community_view.counts.subscribers;
+ this.setState(this.state);
+ }
}
}
}
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Prompt } from "inferno-router";
import {
CreateCommunity,
EditCommunity,
Language,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
capitalizeFirstLetter,
+ myAuth,
randomStr,
wsClient,
wsSubscribe,
import { MarkdownTextArea } from "../common/markdown-textarea";
interface CommunityFormProps {
- community_view: Option<CommunityView>; // If a community is given, that means this is an edit
+ community_view?: CommunityView; // If a community is given, that means this is an edit
allLanguages: Language[];
siteLanguages: number[];
- communityLanguages: Option<number[]>;
+ communityLanguages?: number[];
onCancel?(): any;
onCreate?(community: CommunityView): any;
onEdit?(community: CommunityView): any;
}
interface CommunityFormState {
- communityForm: CreateCommunity;
+ form: {
+ name?: string;
+ title?: string;
+ description?: string;
+ icon?: string;
+ banner?: string;
+ nsfw?: boolean;
+ posting_restricted_to_mods?: boolean;
+ discussion_languages?: number[];
+ };
loading: boolean;
}
CommunityFormState
> {
private id = `community-form-${randomStr()}`;
- private subscription: Subscription;
-
- private emptyState: CommunityFormState = {
- communityForm: new CreateCommunity({
- name: undefined,
- title: undefined,
- description: None,
- discussion_languages: this.props.communityLanguages,
- nsfw: None,
- icon: None,
- banner: None,
- posting_restricted_to_mods: None,
- auth: undefined,
- }),
+ private subscription?: Subscription;
+
+ state: CommunityFormState = {
+ form: {},
loading: false,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.handleCommunityDescriptionChange =
this.handleCommunityDescriptionChange.bind(this);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
+ let cv = this.props.community_view;
- if (this.props.community_view.isSome()) {
- let cv = this.props.community_view.unwrap();
+ if (cv) {
this.state = {
- ...this.state,
- communityForm: new CreateCommunity({
+ form: {
name: cv.community.name,
title: cv.community.title,
description: cv.community.description,
- nsfw: Some(cv.community.nsfw),
+ nsfw: cv.community.nsfw,
icon: cv.community.icon,
banner: cv.community.banner,
- posting_restricted_to_mods: Some(
- cv.community.posting_restricted_to_mods
- ),
+ posting_restricted_to_mods: cv.community.posting_restricted_to_mods,
discussion_languages: this.props.communityLanguages,
- auth: undefined,
- }),
+ },
+ loading: false,
};
}
}
componentDidUpdate() {
if (
!this.state.loading &&
- (this.state.communityForm.name ||
- this.state.communityForm.title ||
- this.state.communityForm.description.isSome())
+ (this.state.form.name ||
+ this.state.form.title ||
+ this.state.form.description)
) {
window.onbeforeunload = () => true;
} else {
- window.onbeforeunload = undefined;
+ window.onbeforeunload = null;
}
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
window.onbeforeunload = null;
}
<Prompt
when={
!this.state.loading &&
- (this.state.communityForm.name ||
- this.state.communityForm.title ||
- this.state.communityForm.description.isSome())
+ (this.state.form.name ||
+ this.state.form.title ||
+ this.state.form.description)
}
message={i18n.t("block_leaving")}
/>
<form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
- {this.props.community_view.isNone() && (
+ {!this.props.community_view && (
<div className="form-group row">
<label
className="col-12 col-sm-2 col-form-label"
type="text"
id="community-name"
className="form-control"
- value={this.state.communityForm.name}
+ value={this.state.form.name}
onInput={linkEvent(this, this.handleCommunityNameChange)}
required
minLength={3}
<input
type="text"
id="community-title"
- value={this.state.communityForm.title}
+ value={this.state.form.title}
onInput={linkEvent(this, this.handleCommunityTitleChange)}
className="form-control"
required
<div className="col-12 col-sm-10">
<ImageUploadForm
uploadTitle={i18n.t("upload_icon")}
- imageSrc={this.state.communityForm.icon}
+ imageSrc={this.state.form.icon}
onUpload={this.handleIconUpload}
onRemove={this.handleIconRemove}
rounded
<div className="col-12 col-sm-10">
<ImageUploadForm
uploadTitle={i18n.t("upload_banner")}
- imageSrc={this.state.communityForm.banner}
+ imageSrc={this.state.form.banner}
onUpload={this.handleBannerUpload}
onRemove={this.handleBannerRemove}
/>
</label>
<div className="col-12 col-sm-10">
<MarkdownTextArea
- initialContent={this.state.communityForm.description}
- initialLanguageId={None}
- placeholder={Some("description")}
- buttonTitle={None}
- maxLength={None}
+ initialContent={this.state.form.description}
+ placeholder={i18n.t("description")}
onContentChange={this.handleCommunityDescriptionChange}
allLanguages={[]}
siteLanguages={[]}
className="form-check-input position-static"
id="community-nsfw"
type="checkbox"
- checked={toUndefined(this.state.communityForm.nsfw)}
+ checked={this.state.form.nsfw}
onChange={linkEvent(this, this.handleCommunityNsfwChange)}
/>
</div>
className="form-check-input position-static"
id="community-only-mods-can-post"
type="checkbox"
- checked={toUndefined(
- this.state.communityForm.posting_restricted_to_mods
- )}
+ checked={this.state.form.posting_restricted_to_mods}
onChange={linkEvent(
this,
this.handleCommunityPostingRestrictedToMods
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
showSite
- selectedLanguageIds={this.state.communityForm.discussion_languages}
+ selectedLanguageIds={this.state.form.discussion_languages}
multiple={true}
onChange={this.handleDiscussionLanguageChange}
/>
>
{this.state.loading ? (
<Spinner />
- ) : this.props.community_view.isSome() ? (
+ ) : this.props.community_view ? (
capitalizeFirstLetter(i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("create"))
)}
</button>
- {this.props.community_view.isSome() && (
+ {this.props.community_view && (
<button
type="button"
className="btn btn-secondary"
handleCreateCommunitySubmit(i: CommunityForm, event: any) {
event.preventDefault();
i.setState({ loading: true });
- let cForm = i.state.communityForm;
- cForm.auth = auth().unwrap();
+ let cForm = i.state.form;
+ let auth = myAuth();
- i.props.community_view.match({
- some: cv => {
- let form = new EditCommunity({
+ let cv = i.props.community_view;
+
+ if (auth) {
+ if (cv) {
+ let form: EditCommunity = {
community_id: cv.community.id,
- title: Some(cForm.title),
+ title: cForm.title,
description: cForm.description,
icon: cForm.icon,
banner: cForm.banner,
nsfw: cForm.nsfw,
posting_restricted_to_mods: cForm.posting_restricted_to_mods,
discussion_languages: cForm.discussion_languages,
- auth: cForm.auth,
- });
+ auth,
+ };
WebSocketService.Instance.send(wsClient.editCommunity(form));
- },
- none: () => {
- WebSocketService.Instance.send(
- wsClient.createCommunity(i.state.communityForm)
- );
- },
- });
+ } else {
+ if (cForm.title && cForm.name) {
+ let form: CreateCommunity = {
+ name: cForm.name,
+ title: cForm.title,
+ description: cForm.description,
+ icon: cForm.icon,
+ banner: cForm.banner,
+ nsfw: cForm.nsfw,
+ posting_restricted_to_mods: cForm.posting_restricted_to_mods,
+ discussion_languages: cForm.discussion_languages,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.createCommunity(form));
+ }
+ }
+ }
i.setState(i.state);
}
handleCommunityNameChange(i: CommunityForm, event: any) {
- i.state.communityForm.name = event.target.value;
+ i.state.form.name = event.target.value;
i.setState(i.state);
}
handleCommunityTitleChange(i: CommunityForm, event: any) {
- i.state.communityForm.title = event.target.value;
+ i.state.form.title = event.target.value;
i.setState(i.state);
}
handleCommunityDescriptionChange(val: string) {
- this.setState(s => ((s.communityForm.description = Some(val)), s));
+ this.setState(s => ((s.form.description = val), s));
}
handleCommunityNsfwChange(i: CommunityForm, event: any) {
- i.state.communityForm.nsfw = Some(event.target.checked);
+ i.state.form.nsfw = event.target.checked;
i.setState(i.state);
}
handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
- i.state.communityForm.posting_restricted_to_mods = Some(
- event.target.checked
- );
+ i.state.form.posting_restricted_to_mods = event.target.checked;
i.setState(i.state);
}
handleCancel(i: CommunityForm) {
- i.props.onCancel();
+ i.props.onCancel?.();
}
handleIconUpload(url: string) {
- this.setState(s => ((s.communityForm.icon = Some(url)), s));
+ this.setState(s => ((s.form.icon = url), s));
}
handleIconRemove() {
- this.setState(s => ((s.communityForm.icon = Some("")), s));
+ this.setState(s => ((s.form.icon = ""), s));
}
handleBannerUpload(url: string) {
- this.setState(s => ((s.communityForm.banner = Some(url)), s));
+ this.setState(s => ((s.form.banner = url), s));
}
handleBannerRemove() {
- this.setState(s => ((s.communityForm.banner = Some("")), s));
+ this.setState(s => ((s.form.banner = ""), s));
}
handleDiscussionLanguageChange(val: number[]) {
- this.setState(s => ((s.communityForm.discussion_languages = Some(val)), s));
+ this.setState(s => ((s.form.discussion_languages = val), s));
}
parseMessage(msg: any) {
this.setState({ loading: false });
return;
} else if (op == UserOperation.CreateCommunity) {
- let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
- this.props.onCreate(data.community_view);
+ let data = wsJsonToRes<CommunityResponse>(msg);
+ this.props.onCreate?.(data.community_view);
// Update myUserInfo
let community = data.community_view.community;
- UserService.Instance.myUserInfo.match({
- some: mui => {
- let person = mui.local_user_view.person;
- mui.follows.push({
- community,
- follower: person,
- });
- mui.moderates.push({
- community,
- moderator: person,
- });
- },
- none: void 0,
- });
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ let person = mui.local_user_view.person;
+ mui.follows.push({
+ community,
+ follower: person,
+ });
+ mui.moderates.push({
+ community,
+ moderator: person,
+ });
+ }
} else if (op == UserOperation.EditCommunity) {
- let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
+ let data = wsJsonToRes<CommunityResponse>(msg);
this.setState({ loading: false });
- this.props.onEdit(data.community_view);
+ this.props.onEdit?.(data.community_view);
let community = data.community_view.community;
- UserService.Instance.myUserInfo.match({
- some: mui => {
- let followFound = mui.follows.findIndex(
- f => f.community.id == community.id
- );
- if (followFound) {
- mui.follows[followFound].community = community;
- }
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ let followFound = mui.follows.findIndex(
+ f => f.community.id == community.id
+ );
+ if (followFound) {
+ mui.follows[followFound].community = community;
+ }
- let moderatesFound = mui.moderates.findIndex(
- f => f.community.id == community.id
- );
- if (moderatesFound) {
- mui.moderates[moderatesFound].community = community;
- }
- },
- none: void 0,
- });
+ let moderatesFound = mui.moderates.findIndex(
+ f => f.community.id == community.id
+ );
+ if (moderatesFound) {
+ mui.moderates[moderatesFound].community = community;
+ }
+ }
}
}
}
import { PictrsImage } from "../common/pictrs-image";
interface CommunityLinkProps {
- // TODO figure this out better
community: CommunitySafe;
realLink?: boolean;
useApubName?: boolean;
}
avatarAndName(displayName: string) {
+ let icon = this.props.community.icon;
return (
<>
- {!this.props.hideAvatar &&
- showAvatars() &&
- this.props.community.icon.match({
- some: icon => <PictrsImage src={icon} icon />,
- none: <></>,
- })}
+ {!this.props.hideAvatar && showAvatars() && icon && (
+ <PictrsImage src={icon} icon />
+ )}
<span className="overflow-wrap-anywhere">{displayName}</span>
</>
);
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
AddModToCommunityResponse,
PostView,
PurgeItemResponse,
SortType,
- toOption,
UserOperation,
wsJsonToRes,
wsUserOp,
} from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
commentsToFlatNodes,
communityRSSUrl,
createCommentLikeRes,
getPageFromProps,
getSortTypeFromProps,
isPostBlocked,
+ myAuth,
notifyPost,
nsfwCheck,
postToCommentSortType,
import { CommunityLink } from "./community-link";
interface State {
- communityRes: Option<GetCommunityResponse>;
+ communityRes?: GetCommunityResponse;
siteRes: GetSiteResponse;
communityName: string;
communityLoading: boolean;
}
export class Community extends Component<any, State> {
- private isoData = setIsoData(
- this.context,
- GetCommunityResponse,
- GetPostsResponse,
- GetCommentsResponse
- );
- private subscription: Subscription;
- private emptyState: State = {
- communityRes: None,
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: State = {
communityName: this.props.match.params.name,
communityLoading: true,
postsLoading: true,
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
this.handleDataTypeChange = this.handleDataTypeChange.bind(this);
this.handlePageChange = this.handlePageChange.bind(this);
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- communityRes: Some(this.isoData.routeData[0] as GetCommunityResponse),
+ communityRes: this.isoData.routeData[0] as GetCommunityResponse,
};
- let postsRes = Some(this.isoData.routeData[1] as GetPostsResponse);
- let commentsRes = Some(this.isoData.routeData[2] as GetCommentsResponse);
+ let postsRes = this.isoData.routeData[1] as GetPostsResponse | undefined;
+ let commentsRes = this.isoData.routeData[2] as
+ | GetCommentsResponse
+ | undefined;
- if (postsRes.isSome()) {
- this.state = { ...this.state, posts: postsRes.unwrap().posts };
+ if (postsRes) {
+ this.state = { ...this.state, posts: postsRes.posts };
}
- if (commentsRes.isSome()) {
- this.state = { ...this.state, comments: commentsRes.unwrap().comments };
+ if (commentsRes) {
+ this.state = { ...this.state, comments: commentsRes.comments };
}
this.state = {
}
fetchCommunity() {
- let form = new GetCommunity({
- name: Some(this.state.communityName),
- id: None,
- auth: auth(false).ok(),
- });
+ let form: GetCommunity = {
+ name: this.state.communityName,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(wsClient.getCommunity(form));
}
componentWillUnmount() {
saveScrollPosition(this.context);
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
static getDerivedStateFromProps(props: any): CommunityProps {
let promises: Promise<any>[] = [];
let communityName = pathSplit[2];
- let communityForm = new GetCommunity({
- name: Some(communityName),
- id: None,
+ let communityForm: GetCommunity = {
+ name: communityName,
auth: req.auth,
- });
+ };
promises.push(req.client.getCommunity(communityForm));
let dataType: DataType = pathSplit[4]
? DataType[pathSplit[4]]
: DataType.Post;
- let sort: Option<SortType> = toOption(
- pathSplit[6]
- ? SortType[pathSplit[6]]
- : UserService.Instance.myUserInfo.match({
- some: mui =>
- Object.values(SortType)[
- mui.local_user_view.local_user.default_sort_type
- ],
- none: SortType.Active,
- })
- );
+ let mui = UserService.Instance.myUserInfo;
+
+ let sort: SortType = pathSplit[6]
+ ? SortType[pathSplit[6]]
+ : mui
+ ? Object.values(SortType)[
+ mui.local_user_view.local_user.default_sort_type
+ ]
+ : SortType.Active;
- let page = toOption(pathSplit[8] ? Number(pathSplit[8]) : 1);
+ let page = pathSplit[8] ? Number(pathSplit[8]) : 1;
if (dataType == DataType.Post) {
- let getPostsForm = new GetPosts({
- community_name: Some(communityName),
- community_id: None,
+ let getPostsForm: GetPosts = {
+ community_name: communityName,
page,
- limit: Some(fetchLimit),
+ limit: fetchLimit,
sort,
- type_: Some(ListingType.All),
- saved_only: Some(false),
+ type_: ListingType.All,
+ saved_only: false,
auth: req.auth,
- });
+ };
promises.push(req.client.getPosts(getPostsForm));
promises.push(Promise.resolve());
} else {
- let getCommentsForm = new GetComments({
- community_name: Some(communityName),
- community_id: None,
+ let getCommentsForm: GetComments = {
+ community_name: communityName,
page,
- limit: Some(fetchLimit),
- max_depth: None,
- sort: sort.map(postToCommentSortType),
- type_: Some(ListingType.All),
- saved_only: Some(false),
- post_id: None,
- parent_id: None,
+ limit: fetchLimit,
+ sort: postToCommentSortType(sort),
+ type_: ListingType.All,
+ saved_only: false,
auth: req.auth,
- });
+ };
promises.push(Promise.resolve());
promises.push(req.client.getComments(getCommentsForm));
}
}
get documentTitle(): string {
- return this.state.communityRes.match({
- some: res =>
- `${res.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`,
- none: "",
- });
+ let cRes = this.state.communityRes;
+ return cRes
+ ? `${cRes.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`
+ : "";
}
render() {
// For some reason, this returns an empty vec if it matches the site langs
- let communityLangs = this.state.communityRes.map(r => {
- let langs = r.discussion_languages;
- if (langs.length == 0) {
- return this.state.siteRes.all_languages.map(l => l.id);
- } else {
- return langs;
- }
- });
+ let res = this.state.communityRes;
+ let communityLangs =
+ res?.discussion_languages.length == 0
+ ? this.state.siteRes.all_languages.map(l => l.id)
+ : res?.discussion_languages;
return (
<div className="container-lg">
<Spinner large />
</h5>
) : (
- this.state.communityRes.match({
- some: res => (
- <>
- <HtmlTags
- title={this.documentTitle}
- path={this.context.router.route.match.url}
- description={res.community_view.community.description}
- image={res.community_view.community.icon}
- />
-
- <div className="row">
- <div className="col-12 col-md-8">
- {this.communityInfo()}
- <div className="d-block d-md-none">
- <button
- className="btn btn-secondary d-inline-block mb-2 mr-3"
- onClick={linkEvent(this, this.handleShowSidebarMobile)}
- >
- {i18n.t("sidebar")}{" "}
- <Icon
- icon={
- this.state.showSidebarMobile
- ? `minus-square`
- : `plus-square`
+ res && (
+ <>
+ <HtmlTags
+ title={this.documentTitle}
+ path={this.context.router.route.match.url}
+ description={res.community_view.community.description}
+ image={res.community_view.community.icon}
+ />
+
+ <div className="row">
+ <div className="col-12 col-md-8">
+ {this.communityInfo()}
+ <div className="d-block d-md-none">
+ <button
+ className="btn btn-secondary d-inline-block mb-2 mr-3"
+ onClick={linkEvent(this, this.handleShowSidebarMobile)}
+ >
+ {i18n.t("sidebar")}{" "}
+ <Icon
+ icon={
+ this.state.showSidebarMobile
+ ? `minus-square`
+ : `plus-square`
+ }
+ classes="icon-inline"
+ />
+ </button>
+ {this.state.showSidebarMobile && (
+ <>
+ <Sidebar
+ community_view={res.community_view}
+ moderators={res.moderators}
+ admins={this.state.siteRes.admins}
+ online={res.online}
+ enableNsfw={enableNsfw(this.state.siteRes)}
+ editable
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={
+ this.state.siteRes.discussion_languages
}
- classes="icon-inline"
+ communityLanguages={communityLangs}
/>
- </button>
- {this.state.showSidebarMobile && (
- <>
- <Sidebar
- community_view={res.community_view}
- moderators={res.moderators}
- admins={this.state.siteRes.admins}
- online={res.online}
- enableNsfw={enableNsfw(this.state.siteRes)}
- editable
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={
- this.state.siteRes.discussion_languages
- }
- communityLanguages={communityLangs}
- />
- {!res.community_view.community.local &&
- res.site.match({
- some: site => (
- <SiteSidebar
- site={site}
- showLocal={showLocal(this.isoData)}
- admins={None}
- counts={None}
- online={None}
- />
- ),
- none: <></>,
- })}
- </>
- )}
- </div>
- {this.selects()}
- {this.listings()}
- <Paginator
- page={this.state.page}
- onChange={this.handlePageChange}
- />
- </div>
- <div className="d-none d-md-block col-md-4">
- <Sidebar
- community_view={res.community_view}
- moderators={res.moderators}
- admins={this.state.siteRes.admins}
- online={res.online}
- enableNsfw={enableNsfw(this.state.siteRes)}
- editable
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={this.state.siteRes.discussion_languages}
- communityLanguages={communityLangs}
- />
- {!res.community_view.community.local &&
- res.site.match({
- some: site => (
+ {!res.community_view.community.local && res.site && (
<SiteSidebar
- site={site}
+ site={res.site}
showLocal={showLocal(this.isoData)}
- admins={None}
- counts={None}
- online={None}
/>
- ),
- none: <></>,
- })}
+ )}
+ </>
+ )}
</div>
+ {this.selects()}
+ {this.listings()}
+ <Paginator
+ page={this.state.page}
+ onChange={this.handlePageChange}
+ />
</div>
- </>
- ),
- none: <></>,
- })
+ <div className="d-none d-md-block col-md-4">
+ <Sidebar
+ community_view={res.community_view}
+ moderators={res.moderators}
+ admins={this.state.siteRes.admins}
+ online={res.online}
+ enableNsfw={enableNsfw(this.state.siteRes)}
+ editable
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ communityLanguages={communityLangs}
+ />
+ {!res.community_view.community.local && res.site && (
+ <SiteSidebar
+ site={res.site}
+ showLocal={showLocal(this.isoData)}
+ />
+ )}
+ </div>
+ </div>
+ </>
+ )
)}
</div>
);
noIndent
showContext
enableDownvotes={enableDownvotes(this.state.siteRes)}
- moderators={this.state.communityRes.map(r => r.moderators)}
- admins={Some(this.state.siteRes.admins)}
- maxCommentsShown={None}
+ moderators={this.state.communityRes?.moderators}
+ admins={this.state.siteRes.admins}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
/>
}
communityInfo() {
- return this.state.communityRes
- .map(r => r.community_view.community)
- .match({
- some: community => (
- <div className="mb-2">
- <BannerIconHeader banner={community.banner} icon={community.icon} />
- <h5 className="mb-0 overflow-wrap-anywhere">{community.title}</h5>
- <CommunityLink
- community={community}
- realLink
- useApubName
- muted
- hideAvatar
- />
- </div>
- ),
- none: <></>,
- });
+ let community = this.state.communityRes?.community_view.community;
+ return (
+ community && (
+ <div className="mb-2">
+ <BannerIconHeader banner={community.banner} icon={community.icon} />
+ <h5 className="mb-0 overflow-wrap-anywhere">{community.title}</h5>
+ <CommunityLink
+ community={community}
+ realLink
+ useApubName
+ muted
+ hideAvatar
+ />
+ </div>
+ )
+ );
}
selects() {
- let communityRss = this.state.communityRes.map(r =>
- communityRSSUrl(r.community_view.community.actor_id, this.state.sort)
- );
+ // let communityRss = this.state.communityRes.map(r =>
+ // communityRSSUrl(r.community_view.community.actor_id, this.state.sort)
+ // );
+ let res = this.state.communityRes;
+ let communityRss = res
+ ? communityRSSUrl(res.community_view.community.actor_id, this.state.sort)
+ : undefined;
+
return (
<div className="mb-3">
<span className="mr-3">
<span className="mr-2">
<SortSelect sort={this.state.sort} onChange={this.handleSortChange} />
</span>
- {communityRss.match({
- some: rss => (
- <>
- <a href={rss} title="RSS" rel={relTags}>
- <Icon icon="rss" classes="text-muted small" />
- </a>
- <link rel="alternate" type="application/atom+xml" href={rss} />
- </>
- ),
- none: <></>,
- })}
+ {communityRss && (
+ <>
+ <a href={communityRss} title="RSS" rel={relTags}>
+ <Icon icon="rss" classes="text-muted small" />
+ </a>
+ <link
+ rel="alternate"
+ type="application/atom+xml"
+ href={communityRss}
+ />
+ </>
+ )}
</div>
);
}
fetchData() {
if (this.state.dataType == DataType.Post) {
- let form = new GetPosts({
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- sort: Some(this.state.sort),
- type_: Some(ListingType.All),
- community_name: Some(this.state.communityName),
- community_id: None,
- saved_only: Some(false),
- auth: auth(false).ok(),
- });
+ let form: GetPosts = {
+ page: this.state.page,
+ limit: fetchLimit,
+ sort: this.state.sort,
+ type_: ListingType.All,
+ community_name: this.state.communityName,
+ saved_only: false,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(wsClient.getPosts(form));
} else {
- let form = new GetComments({
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- max_depth: None,
- sort: Some(postToCommentSortType(this.state.sort)),
- type_: Some(ListingType.All),
- community_name: Some(this.state.communityName),
- community_id: None,
- saved_only: Some(false),
- post_id: None,
- parent_id: None,
- auth: auth(false).ok(),
- });
+ let form: GetComments = {
+ page: this.state.page,
+ limit: fetchLimit,
+ sort: postToCommentSortType(this.state.sort),
+ type_: ListingType.All,
+ community_name: this.state.communityName,
+ saved_only: false,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(wsClient.getComments(form));
}
}
parseMessage(msg: any) {
let op = wsUserOp(msg);
console.log(msg);
+ let res = this.state.communityRes;
if (msg.error) {
toast(i18n.t(msg.error), "danger");
this.context.router.history.push("/");
return;
} else if (msg.reconnect) {
- this.state.communityRes.match({
- some: res => {
- WebSocketService.Instance.send(
- wsClient.communityJoin({
- community_id: res.community_view.community.id,
- })
- );
- },
- none: void 0,
- });
+ if (res) {
+ WebSocketService.Instance.send(
+ wsClient.communityJoin({
+ community_id: res.community_view.community.id,
+ })
+ );
+ }
this.fetchData();
} else if (op == UserOperation.GetCommunity) {
- let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
- this.setState({ communityRes: Some(data), communityLoading: false });
+ let data = wsJsonToRes<GetCommunityResponse>(msg);
+ this.setState({ communityRes: data, communityLoading: false });
// TODO why is there no auth in this form?
WebSocketService.Instance.send(
wsClient.communityJoin({
op == UserOperation.DeleteCommunity ||
op == UserOperation.RemoveCommunity
) {
- let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
- this.state.communityRes.match({
- some: res => {
- res.community_view = data.community_view;
- res.discussion_languages = data.discussion_languages;
- },
- none: void 0,
- });
+ let data = wsJsonToRes<CommunityResponse>(msg);
+ if (res) {
+ res.community_view = data.community_view;
+ res.discussion_languages = data.discussion_languages;
+ }
this.setState(this.state);
} else if (op == UserOperation.FollowCommunity) {
- let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
- this.state.communityRes.match({
- some: res => {
- res.community_view.subscribed = data.community_view.subscribed;
- res.community_view.counts.subscribers =
- data.community_view.counts.subscribers;
- },
- none: void 0,
- });
+ let data = wsJsonToRes<CommunityResponse>(msg);
+ if (res) {
+ res.community_view.subscribed = data.community_view.subscribed;
+ res.community_view.counts.subscribers =
+ data.community_view.counts.subscribers;
+ }
this.setState(this.state);
} else if (op == UserOperation.GetPosts) {
- let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
+ let data = wsJsonToRes<GetPostsResponse>(msg);
this.setState({ posts: data.posts, postsLoading: false });
restoreScrollPosition(this.context);
setupTippy();
op == UserOperation.FeaturePost ||
op == UserOperation.SavePost
) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ let data = wsJsonToRes<PostResponse>(msg);
editPostFindRes(data.post_view, this.state.posts);
this.setState(this.state);
} else if (op == UserOperation.CreatePost) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ let data = wsJsonToRes<PostResponse>(msg);
- let showPostNotifs = UserService.Instance.myUserInfo
- .map(m => m.local_user_view.local_user.show_new_post_notifs)
- .unwrapOr(false);
+ let showPostNotifs =
+ UserService.Instance.myUserInfo?.local_user_view.local_user
+ .show_new_post_notifs;
// Only push these if you're on the first page, you pass the nsfw check, and it isn't blocked
//
this.setState(this.state);
}
} else if (op == UserOperation.CreatePostLike) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ let data = wsJsonToRes<PostResponse>(msg);
createPostLikeFindRes(data.post_view, this.state.posts);
this.setState(this.state);
} else if (op == UserOperation.AddModToCommunity) {
- let data = wsJsonToRes<AddModToCommunityResponse>(
- msg,
- AddModToCommunityResponse
- );
- this.state.communityRes.match({
- some: res => (res.moderators = data.moderators),
- none: void 0,
- });
+ let data = wsJsonToRes<AddModToCommunityResponse>(msg);
+ if (res) {
+ res.moderators = data.moderators;
+ }
this.setState(this.state);
} else if (op == UserOperation.BanFromCommunity) {
- let data = wsJsonToRes<BanFromCommunityResponse>(
- msg,
- BanFromCommunityResponse
- );
+ let data = wsJsonToRes<BanFromCommunityResponse>(msg);
// TODO this might be incorrect
this.state.posts
this.setState(this.state);
} else if (op == UserOperation.GetComments) {
- let data = wsJsonToRes<GetCommentsResponse>(msg, GetCommentsResponse);
+ let data = wsJsonToRes<GetCommentsResponse>(msg);
this.setState({ comments: data.comments, commentsLoading: false });
} else if (
op == UserOperation.EditComment ||
op == UserOperation.DeleteComment ||
op == UserOperation.RemoveComment
) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
editCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
// Necessary since it might be a user reply
if (data.form_id) {
this.setState(this.state);
}
} else if (op == UserOperation.SaveComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
saveCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
createCommentLikeRes(data.comment_view, this.state.comments);
this.setState(this.state);
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
+ let data = wsJsonToRes<BlockPersonResponse>(msg);
updatePersonBlock(data);
} else if (op == UserOperation.CreatePostReport) {
- let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+ let data = wsJsonToRes<PostReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
} else if (op == UserOperation.CreateCommentReport) {
- let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+ let data = wsJsonToRes<CommentReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
} else if (op == UserOperation.PurgeCommunity) {
- let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+ let data = wsJsonToRes<PurgeItemResponse>(msg);
if (data.success) {
toast(i18n.t("purge_success"));
this.context.router.history.push(`/`);
}
} else if (op == UserOperation.BlockCommunity) {
- let data = wsJsonToRes<BlockCommunityResponse>(
- msg,
- BlockCommunityResponse
- );
- this.state.communityRes.match({
- some: res => (res.community_view.blocked = data.blocked),
- none: void 0,
- });
+ let data = wsJsonToRes<BlockCommunityResponse>(msg);
+ if (res) {
+ res.community_view.blocked = data.blocked;
+ }
updateCommunityBlock(data);
this.setState(this.state);
}
-import { None, Some } from "@sniptt/monads";
import { Component } from "inferno";
import { CommunityView, GetSiteResponse } from "lemmy-js-client";
import { Subscription } from "rxjs";
export class CreateCommunity extends Component<any, CreateCommunityState> {
private isoData = setIsoData(this.context);
- private subscription: Subscription;
- private emptyState: CreateCommunityState = {
+ private subscription?: Subscription;
+ state: CreateCommunityState = {
siteRes: this.isoData.site_res,
loading: false,
};
constructor(props: any, context: any) {
super(props, context);
this.handleCommunityCreate = this.handleCommunityCreate.bind(this);
- this.state = this.emptyState;
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
- if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+ if (!UserService.Instance.myUserInfo && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`);
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
{this.state.loading ? (
<h5>
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
<h5>{i18n.t("create_community")}</h5>
<CommunityForm
- community_view={None}
onCreate={this.handleCommunityCreate}
enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
- communityLanguages={Some(
- this.state.siteRes.discussion_languages
- )}
+ communityLanguages={this.state.siteRes.discussion_languages}
/>
</div>
</div>
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
import {
PurgeCommunity,
RemoveCommunity,
SubscribedType,
- toUndefined,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
amAdmin,
amMod,
amTopMod,
- auth,
getUnixTime,
mdToHtml,
+ myAuth,
numToSI,
wsClient,
} from "../../utils";
admins: PersonViewSafe[];
allLanguages: Language[];
siteLanguages: number[];
- communityLanguages: Option<number[]>;
+ communityLanguages?: number[];
online: number;
enableNsfw?: boolean;
showIcon?: boolean;
}
interface SidebarState {
- removeReason: Option<string>;
- removeExpires: Option<string>;
+ removeReason?: string;
+ removeExpires?: string;
showEdit: boolean;
showRemoveDialog: boolean;
showPurgeDialog: boolean;
- purgeReason: Option<string>;
+ purgeReason?: string;
purgeLoading: boolean;
showConfirmLeaveModTeam: boolean;
}
export class Sidebar extends Component<SidebarProps, SidebarState> {
- private emptyState: SidebarState = {
+ state: SidebarState = {
showEdit: false,
showRemoveDialog: false,
- removeReason: None,
- removeExpires: None,
showPurgeDialog: false,
- purgeReason: None,
purgeLoading: false,
showConfirmLeaveModTeam: false,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleEditCommunity = this.handleEditCommunity.bind(this);
this.handleEditCancel = this.handleEditCancel.bind(this);
}
this.sidebar()
) : (
<CommunityForm
- community_view={Some(this.props.community_view)}
+ community_view={this.props.community_view}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
communityLanguages={this.props.communityLanguages}
}
description() {
- let description = this.props.community_view.community.description;
- return description.match({
- some: desc => (
+ let desc = this.props.community_view.community.description;
+ return (
+ desc && (
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(desc)} />
- ),
- none: <></>,
- });
+ )
+ );
}
adminButtons() {
return (
<>
<ul className="list-inline mb-1 text-muted font-weight-bold">
- {amMod(Some(this.props.moderators)) && (
+ {amMod(this.props.moderators) && (
<>
<li className="list-inline-item-action">
<button
<Icon icon="edit" classes="icon-inline" />
</button>
</li>
- {!amTopMod(Some(this.props.moderators)) &&
+ {!amTopMod(this.props.moderators) &&
(!this.state.showConfirmLeaveModTeam ? (
<li className="list-inline-item-action">
<button
</li>
</>
))}
- {amTopMod(Some(this.props.moderators)) && (
+ {amTopMod(this.props.moderators) && (
<li className="list-inline-item-action">
<button
className="btn btn-link text-muted d-inline-block"
id="remove-reason"
className="form-control mr-2"
placeholder={i18n.t("optional")}
- value={toUndefined(this.state.removeReason)}
+ value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/>
</div>
id="purge-reason"
className="form-control mr-2"
placeholder={i18n.t("reason")}
- value={toUndefined(this.state.purgeReason)}
+ value={this.state.purgeReason}
onInput={linkEvent(this, this.handlePurgeReasonChange)}
/>
</div>
handleDeleteClick(i: Sidebar, event: any) {
event.preventDefault();
- let deleteForm = new DeleteCommunity({
- community_id: i.props.community_view.community.id,
- deleted: !i.props.community_view.community.deleted,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.deleteCommunity(deleteForm));
+ let auth = myAuth();
+ if (auth) {
+ let deleteForm: DeleteCommunity = {
+ community_id: i.props.community_view.community.id,
+ deleted: !i.props.community_view.community.deleted,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.deleteCommunity(deleteForm));
+ }
}
handleShowConfirmLeaveModTeamClick(i: Sidebar) {
}
handleLeaveModTeamClick(i: Sidebar) {
- UserService.Instance.myUserInfo.match({
- some: mui => {
- let form = new AddModToCommunity({
- person_id: mui.local_user_view.person.id,
- community_id: i.props.community_view.community.id,
- added: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.addModToCommunity(form));
- i.setState({ showConfirmLeaveModTeam: false });
- },
- none: void 0,
- });
+ let mui = UserService.Instance.myUserInfo;
+ let auth = myAuth();
+ if (auth && mui) {
+ let form: AddModToCommunity = {
+ person_id: mui.local_user_view.person.id,
+ community_id: i.props.community_view.community.id,
+ added: false,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.addModToCommunity(form));
+ i.setState({ showConfirmLeaveModTeam: false });
+ }
}
handleCancelLeaveModTeamClick(i: Sidebar) {
handleUnsubscribe(i: Sidebar, event: any) {
event.preventDefault();
let community_id = i.props.community_view.community.id;
- let form = new FollowCommunity({
- community_id,
- follow: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.followCommunity(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: FollowCommunity = {
+ community_id,
+ follow: false,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
+ }
// Update myUserInfo
- UserService.Instance.myUserInfo.match({
- some: mui =>
- (mui.follows = mui.follows.filter(i => i.community.id != community_id)),
- none: void 0,
- });
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ mui.follows = mui.follows.filter(i => i.community.id != community_id);
+ }
}
handleSubscribe(i: Sidebar, event: any) {
event.preventDefault();
let community_id = i.props.community_view.community.id;
- let form = new FollowCommunity({
- community_id,
- follow: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.followCommunity(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: FollowCommunity = {
+ community_id,
+ follow: true,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.followCommunity(form));
+ }
// Update myUserInfo
- UserService.Instance.myUserInfo.match({
- some: mui =>
- mui.follows.push({
- community: i.props.community_view.community,
- follower: mui.local_user_view.person,
- }),
- none: void 0,
- });
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ mui.follows.push({
+ community: i.props.community_view.community,
+ follower: mui.local_user_view.person,
+ });
+ }
}
get canPost(): boolean {
return (
!this.props.community_view.community.posting_restricted_to_mods ||
- amMod(Some(this.props.moderators)) ||
+ amMod(this.props.moderators) ||
amAdmin()
);
}
}
handleModRemoveReasonChange(i: Sidebar, event: any) {
- i.setState({ removeReason: Some(event.target.value) });
+ i.setState({ removeReason: event.target.value });
}
handleModRemoveExpiresChange(i: Sidebar, event: any) {
- i.setState({ removeExpires: Some(event.target.value) });
+ i.setState({ removeExpires: event.target.value });
}
handleModRemoveSubmit(i: Sidebar, event: any) {
event.preventDefault();
- let removeForm = new RemoveCommunity({
- community_id: i.props.community_view.community.id,
- removed: !i.props.community_view.community.removed,
- reason: i.state.removeReason,
- expires: i.state.removeExpires.map(getUnixTime),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.removeCommunity(removeForm));
-
- i.setState({ showRemoveDialog: false });
+ let auth = myAuth();
+ if (auth) {
+ let removeForm: RemoveCommunity = {
+ community_id: i.props.community_view.community.id,
+ removed: !i.props.community_view.community.removed,
+ reason: i.state.removeReason,
+ expires: getUnixTime(i.state.removeExpires),
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.removeCommunity(removeForm));
+
+ i.setState({ showRemoveDialog: false });
+ }
}
handlePurgeCommunityShow(i: Sidebar) {
}
handlePurgeReasonChange(i: Sidebar, event: any) {
- i.setState({ purgeReason: Some(event.target.value) });
+ i.setState({ purgeReason: event.target.value });
}
handlePurgeSubmit(i: Sidebar, event: any) {
event.preventDefault();
- let form = new PurgeCommunity({
- community_id: i.props.community_view.community.id,
- reason: i.state.purgeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.purgeCommunity(form));
-
- i.setState({ purgeLoading: true });
+ let auth = myAuth();
+ if (auth) {
+ let form: PurgeCommunity = {
+ community_id: i.props.community_view.community.id,
+ reason: i.state.purgeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.purgeCommunity(form));
+ i.setState({ purgeLoading: true });
+ }
}
handleBlock(i: Sidebar, event: any) {
event.preventDefault();
- let blockCommunityForm = new BlockCommunity({
- community_id: i.props.community_view.community.id,
- block: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockCommunityForm: BlockCommunity = {
+ community_id: i.props.community_view.community.id,
+ block: true,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.blockCommunity(blockCommunityForm)
+ );
+ }
}
handleUnblock(i: Sidebar, event: any) {
event.preventDefault();
- let blockCommunityForm = new BlockCommunity({
- community_id: i.props.community_view.community.id,
- block: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockCommunityForm: BlockCommunity = {
+ community_id: i.props.community_view.community.id,
+ block: false,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.blockCommunity(blockCommunityForm)
+ );
+ }
}
}
-import { None } from "@sniptt/monads";
import autosize from "autosize";
import { Component, linkEvent } from "inferno";
import {
import { InitialFetchRequest } from "../../interfaces";
import { WebSocketService } from "../../services";
import {
- auth,
capitalizeFirstLetter,
isBrowser,
+ myAuth,
randomStr,
setIsoData,
showLocal,
export class AdminSettings extends Component<any, AdminSettingsState> {
private siteConfigTextAreaId = `site-config-${randomStr()}`;
- private isoData = setIsoData(this.context, BannedPersonsResponse);
- private subscription: Subscription;
- private emptyState: AdminSettingsState = {
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: AdminSettingsState = {
siteRes: this.isoData.site_res,
banned: [],
loading: true,
- leaveAdminTeamLoading: null,
+ leaveAdminTeamLoading: false,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
loading: false,
};
} else {
- WebSocketService.Instance.send(
- wsClient.getBannedPersons({
- auth: auth().unwrap(),
- })
- );
+ let cAuth = myAuth();
+ if (cAuth) {
+ WebSocketService.Instance.send(
+ wsClient.getBannedPersons({
+ auth: cAuth,
+ })
+ );
+ }
}
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let promises: Promise<any>[] = [];
- let bannedPersonsForm = new GetBannedPersons({ auth: req.auth.unwrap() });
- promises.push(req.client.getBannedPersons(bannedPersonsForm));
+ let auth = req.auth;
+ if (auth) {
+ let bannedPersonsForm: GetBannedPersons = { auth };
+ promises.push(req.client.getBannedPersons(bannedPersonsForm));
+ }
return promises;
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<SiteForm
siteRes={this.state.siteRes}
}
handleLeaveAdminTeam(i: AdminSettings) {
- i.setState({ leaveAdminTeamLoading: true });
- WebSocketService.Instance.send(
- wsClient.leaveAdmin({ auth: auth().unwrap() })
- );
+ let auth = myAuth();
+ if (auth) {
+ i.setState({ leaveAdminTeamLoading: true });
+ WebSocketService.Instance.send(wsClient.leaveAdmin({ auth }));
+ }
}
parseMessage(msg: any) {
this.setState({ loading: false });
return;
} else if (op == UserOperation.EditSite) {
- let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
+ let data = wsJsonToRes<SiteResponse>(msg);
this.setState(s => ((s.siteRes.site_view = data.site_view), s));
toast(i18n.t("site_saved"));
} else if (op == UserOperation.GetBannedPersons) {
- let data = wsJsonToRes<BannedPersonsResponse>(msg, BannedPersonsResponse);
+ let data = wsJsonToRes<BannedPersonsResponse>(msg);
this.setState({ banned: data.banned, loading: false });
} else if (op == UserOperation.LeaveAdmin) {
- let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+ let data = wsJsonToRes<GetSiteResponse>(msg);
this.setState(s => ((s.siteRes.site_view = data.site_view), s));
this.setState({ leaveAdminTeamLoading: false });
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
} from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
canCreateCommunity,
commentsToFlatNodes,
createCommentLikeRes,
isBrowser,
isPostBlocked,
mdToHtml,
+ myAuth,
notifyPost,
nsfwCheck,
postToCommentSortType,
showSidebarMobile: boolean;
subscribedCollapsed: boolean;
loading: boolean;
- tagline: Option<string>;
+ tagline?: string;
}
interface HomeProps {
}
export class Home extends Component<any, HomeState> {
- private isoData = setIsoData(
- this.context,
- GetPostsResponse,
- GetCommentsResponse,
- ListCommunitiesResponse
- );
- private subscription: Subscription;
- private emptyState: HomeState = {
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: HomeState = {
trendingCommunities: [],
siteRes: this.isoData.site_res,
showSubscribedMobile: false,
dataType: getDataTypeFromProps(this.props),
sort: getSortTypeFromProps(this.props),
page: getPageFromProps(this.props),
- tagline: None,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
this.handleDataTypeChange = this.handleDataTypeChange.bind(this);
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
- let postsRes = Some(this.isoData.routeData[0] as GetPostsResponse);
- let commentsRes = Some(this.isoData.routeData[1] as GetCommentsResponse);
- let trendingRes = this.isoData.routeData[2] as ListCommunitiesResponse;
-
- if (postsRes.isSome()) {
- this.state = { ...this.state, posts: postsRes.unwrap().posts };
+ let postsRes = this.isoData.routeData[0] as GetPostsResponse | undefined;
+ let commentsRes = this.isoData.routeData[1] as
+ | GetCommentsResponse
+ | undefined;
+ let trendingRes = this.isoData.routeData[2] as
+ | ListCommunitiesResponse
+ | undefined;
+
+ if (postsRes) {
+ this.state = { ...this.state, posts: postsRes.posts };
}
- if (commentsRes.isSome()) {
- this.state = { ...this.state, comments: commentsRes.unwrap().comments };
+ if (commentsRes) {
+ this.state = { ...this.state, comments: commentsRes.comments };
}
if (isBrowser()) {
const taglines = this.state.siteRes.taglines;
this.state = {
...this.state,
- trendingCommunities: trendingRes.communities,
+ trendingCommunities: trendingRes?.communities ?? [],
loading: false,
- tagline: taglines.map(tls => getRandomFromList(tls).content),
+ tagline: getRandomFromList(taglines)?.content,
};
} else {
this.fetchTrendingCommunities();
}
fetchTrendingCommunities() {
- let listCommunitiesForm = new ListCommunities({
- type_: Some(ListingType.Local),
- sort: Some(SortType.Hot),
- limit: Some(trendingFetchLimit),
- page: None,
- auth: auth(false).ok(),
- });
+ let listCommunitiesForm: ListCommunities = {
+ type_: ListingType.Local,
+ sort: SortType.Hot,
+ limit: trendingFetchLimit,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(
wsClient.listCommunities(listCommunitiesForm)
);
componentWillUnmount() {
saveScrollPosition(this.context);
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
static getDerivedStateFromProps(
let dataType: DataType = pathSplit[3]
? DataType[pathSplit[3]]
: DataType.Post;
+ let mui = UserService.Instance.myUserInfo;
+ let auth = req.auth;
// TODO figure out auth default_listingType, default_sort_type
- let type_: Option<ListingType> = Some(
- pathSplit[5]
- ? ListingType[pathSplit[5]]
- : UserService.Instance.myUserInfo.match({
- some: mui =>
- Object.values(ListingType)[
- mui.local_user_view.local_user.default_listing_type
- ],
- none: ListingType.Local,
- })
- );
- let sort: Option<SortType> = Some(
- pathSplit[7]
- ? SortType[pathSplit[7]]
- : UserService.Instance.myUserInfo.match({
- some: mui =>
- Object.values(SortType)[
- mui.local_user_view.local_user.default_sort_type
- ],
- none: SortType.Active,
- })
- );
-
- let page = Some(pathSplit[9] ? Number(pathSplit[9]) : 1);
+ let type_: ListingType = pathSplit[5]
+ ? ListingType[pathSplit[5]]
+ : mui
+ ? Object.values(ListingType)[
+ mui.local_user_view.local_user.default_listing_type
+ ]
+ : ListingType.Local;
+ let sort: SortType = pathSplit[7]
+ ? SortType[pathSplit[7]]
+ : mui
+ ? (Object.values(SortType)[
+ mui.local_user_view.local_user.default_sort_type
+ ] as SortType)
+ : SortType.Active;
+
+ let page = pathSplit[9] ? Number(pathSplit[9]) : 1;
let promises: Promise<any>[] = [];
if (dataType == DataType.Post) {
- let getPostsForm = new GetPosts({
- community_id: None,
- community_name: None,
+ let getPostsForm: GetPosts = {
type_,
page,
- limit: Some(fetchLimit),
+ limit: fetchLimit,
sort,
- saved_only: Some(false),
- auth: req.auth,
- });
+ saved_only: false,
+ auth,
+ };
promises.push(req.client.getPosts(getPostsForm));
promises.push(Promise.resolve());
} else {
- let getCommentsForm = new GetComments({
- community_id: None,
- community_name: None,
+ let getCommentsForm: GetComments = {
page,
- limit: Some(fetchLimit),
- max_depth: None,
- sort: sort.map(postToCommentSortType),
+ limit: fetchLimit,
+ sort: postToCommentSortType(sort),
type_,
- saved_only: Some(false),
- post_id: None,
- parent_id: None,
- auth: req.auth,
- });
+ saved_only: false,
+ auth,
+ };
promises.push(Promise.resolve());
promises.push(req.client.getComments(getCommentsForm));
}
- let trendingCommunitiesForm = new ListCommunities({
- type_: Some(ListingType.Local),
- sort: Some(SortType.Hot),
- limit: Some(trendingFetchLimit),
- page: None,
- auth: req.auth,
- });
+ let trendingCommunitiesForm: ListCommunities = {
+ type_: ListingType.Local,
+ sort: SortType.Hot,
+ limit: trendingFetchLimit,
+ auth,
+ };
promises.push(req.client.listCommunities(trendingCommunitiesForm));
return promises;
get documentTitle(): string {
let siteView = this.state.siteRes.site_view;
- return this.state.siteRes.site_view.site.description.match({
- some: desc => `${siteView.site.name} - ${desc}`,
- none: siteView.site.name,
- });
+ let desc = this.state.siteRes.site_view.site.description;
+ return desc ? `${siteView.site.name} - ${desc}` : siteView.site.name;
}
render() {
+ let tagline = this.state.tagline;
+
return (
<div className="container-lg">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
{this.state.siteRes.site_view.local_site.site_setup && (
<div className="row">
<main role="main" className="col-12 col-md-8">
- {this.state.tagline.match({
- some: tagline => (
- <div
- id="tagline"
- dangerouslySetInnerHTML={mdToHtml(tagline)}
- ></div>
- ),
- none: <></>,
- })}
+ {tagline && (
+ <div
+ id="tagline"
+ dangerouslySetInnerHTML={mdToHtml(tagline)}
+ ></div>
+ )}
<div className="d-block d-md-none">{this.mobileView()}</div>
{this.posts()}
</main>
}
get hasFollows(): boolean {
- return UserService.Instance.myUserInfo.match({
- some: mui => mui.follows.length > 0,
- none: false,
- });
+ let mui = UserService.Instance.myUserInfo;
+ return !!mui && mui.follows.length > 0;
}
mobileView() {
{this.state.showSidebarMobile && (
<SiteSidebar
site={siteView.site}
- admins={Some(siteRes.admins)}
- counts={Some(siteView.counts)}
- online={Some(siteRes.online)}
+ admins={siteRes.admins}
+ counts={siteView.counts}
+ online={siteRes.online}
showLocal={showLocal(this.isoData)}
/>
)}
</div>
<SiteSidebar
site={siteView.site}
- admins={Some(siteRes.admins)}
- counts={Some(siteView.counts)}
- online={Some(siteRes.online)}
+ admins={siteRes.admins}
+ counts={siteView.counts}
+ online={siteRes.online}
showLocal={showLocal(this.isoData)}
/>
{this.hasFollows && (
</h5>
{!this.state.subscribedCollapsed && (
<ul className="list-inline mb-0">
- {UserService.Instance.myUserInfo
- .map(m => m.follows)
- .unwrapOr([])
- .map(cfv => (
- <li
- key={cfv.community.id}
- className="list-inline-item d-inline-block"
- >
- <CommunityLink community={cfv.community} />
- </li>
- ))}
+ {UserService.Instance.myUserInfo?.follows.map(cfv => (
+ <li
+ key={cfv.community.id}
+ className="list-inline-item d-inline-block"
+ >
+ <CommunityLink community={cfv.community} />
+ </li>
+ ))}
</ul>
)}
</div>
<CommentNodes
nodes={commentsToFlatNodes(this.state.comments)}
viewType={CommentViewType.Flat}
- moderators={None}
- admins={None}
- maxCommentsShown={None}
noIndent
showCommunity
showContext
selects() {
let allRss = `/feeds/all.xml?sort=${this.state.sort}`;
let localRss = `/feeds/local.xml?sort=${this.state.sort}`;
- let frontRss = auth(false)
- .ok()
- .map(auth => `/feeds/front/${auth}.xml?sort=${this.state.sort}`);
+ let auth = myAuth(false);
+ let frontRss = auth
+ ? `/feeds/front/${auth}.xml?sort=${this.state.sort}`
+ : undefined;
return (
<div className="mb-3">
<link rel="alternate" type="application/atom+xml" href={localRss} />
</>
)}
- {this.state.listingType == ListingType.Subscribed &&
- frontRss.match({
- some: rss => (
- <>
- <a href={rss} title="RSS" rel={relTags}>
- <Icon icon="rss" classes="text-muted small" />
- </a>
- <link rel="alternate" type="application/atom+xml" href={rss} />
- </>
- ),
- none: <></>,
- })}
+ {this.state.listingType == ListingType.Subscribed && frontRss && (
+ <>
+ <a href={frontRss} title="RSS" rel={relTags}>
+ <Icon icon="rss" classes="text-muted small" />
+ </a>
+ <link rel="alternate" type="application/atom+xml" href={frontRss} />
+ </>
+ )}
</div>
);
}
}
fetchData() {
+ let auth = myAuth(false);
if (this.state.dataType == DataType.Post) {
- let getPostsForm = new GetPosts({
- community_id: None,
- community_name: None,
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- sort: Some(this.state.sort),
- saved_only: Some(false),
- auth: auth(false).ok(),
- type_: Some(this.state.listingType),
- });
+ let getPostsForm: GetPosts = {
+ page: this.state.page,
+ limit: fetchLimit,
+ sort: this.state.sort,
+ saved_only: false,
+ type_: this.state.listingType,
+ auth,
+ };
WebSocketService.Instance.send(wsClient.getPosts(getPostsForm));
} else {
- let getCommentsForm = new GetComments({
- community_id: None,
- community_name: None,
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- max_depth: None,
- sort: Some(postToCommentSortType(this.state.sort)),
- saved_only: Some(false),
- post_id: None,
- parent_id: None,
- auth: auth(false).ok(),
- type_: Some(this.state.listingType),
- });
+ let getCommentsForm: GetComments = {
+ page: this.state.page,
+ limit: fetchLimit,
+ sort: postToCommentSortType(this.state.sort),
+ saved_only: false,
+ type_: this.state.listingType,
+ auth,
+ };
WebSocketService.Instance.send(wsClient.getComments(getCommentsForm));
}
}
);
this.fetchData();
} else if (op == UserOperation.ListCommunities) {
- let data = wsJsonToRes<ListCommunitiesResponse>(
- msg,
- ListCommunitiesResponse
- );
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg);
this.setState({ trendingCommunities: data.communities });
} else if (op == UserOperation.EditSite) {
- let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
+ let data = wsJsonToRes<SiteResponse>(msg);
this.setState(s => ((s.siteRes.site_view = data.site_view), s));
toast(i18n.t("site_saved"));
} else if (op == UserOperation.GetPosts) {
- let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
+ let data = wsJsonToRes<GetPostsResponse>(msg);
this.setState({ posts: data.posts, loading: false });
WebSocketService.Instance.send(
wsClient.communityJoin({ community_id: 0 })
restoreScrollPosition(this.context);
setupTippy();
} else if (op == UserOperation.CreatePost) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ let data = wsJsonToRes<PostResponse>(msg);
+ let mui = UserService.Instance.myUserInfo;
- let showPostNotifs = UserService.Instance.myUserInfo
- .map(m => m.local_user_view.local_user.show_new_post_notifs)
- .unwrapOr(false);
+ let showPostNotifs = mui?.local_user_view.local_user.show_new_post_notifs;
// Only push these if you're on the first page, you pass the nsfw check, and it isn't blocked
if (
// If you're on subscribed, only push it if you're subscribed.
if (this.state.listingType == ListingType.Subscribed) {
if (
- UserService.Instance.myUserInfo
- .map(m => m.follows)
- .unwrapOr([])
+ mui?.follows
.map(c => c.community.id)
.includes(data.post_view.community.id)
) {
op == UserOperation.FeaturePost ||
op == UserOperation.SavePost
) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ let data = wsJsonToRes<PostResponse>(msg);
editPostFindRes(data.post_view, this.state.posts);
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+ let data = wsJsonToRes<PostResponse>(msg);
createPostLikeFindRes(data.post_view, this.state.posts);
this.setState(this.state);
} else if (op == UserOperation.AddAdmin) {
- let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
+ let data = wsJsonToRes<AddAdminResponse>(msg);
this.setState(s => ((s.siteRes.admins = data.admins), s));
} else if (op == UserOperation.BanPerson) {
- let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
+ let data = wsJsonToRes<BanPersonResponse>(msg);
this.state.posts
.filter(p => p.creator.id == data.person_view.person.id)
.forEach(p => (p.creator.banned = data.banned));
this.setState(this.state);
} else if (op == UserOperation.GetComments) {
- let data = wsJsonToRes<GetCommentsResponse>(msg, GetCommentsResponse);
+ let data = wsJsonToRes<GetCommentsResponse>(msg);
this.setState({ comments: data.comments, loading: false });
} else if (
op == UserOperation.EditComment ||
op == UserOperation.DeleteComment ||
op == UserOperation.RemoveComment
) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
editCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
// Necessary since it might be a user reply
if (data.form_id) {
// If you're on subscribed, only push it if you're subscribed.
if (this.state.listingType == ListingType.Subscribed) {
if (
- UserService.Instance.myUserInfo
- .map(m => m.follows)
- .unwrapOr([])
+ UserService.Instance.myUserInfo?.follows
.map(c => c.community.id)
.includes(data.comment_view.community.id)
) {
this.setState(this.state);
}
} else if (op == UserOperation.SaveComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
saveCommentRes(data.comment_view, this.state.comments);
this.setState(this.state);
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
createCommentLikeRes(data.comment_view, this.state.comments);
this.setState(this.state);
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
+ let data = wsJsonToRes<BlockPersonResponse>(msg);
updatePersonBlock(data);
} else if (op == UserOperation.CreatePostReport) {
- let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+ let data = wsJsonToRes<PostReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
} else if (op == UserOperation.CreateCommentReport) {
- let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+ let data = wsJsonToRes<CommentReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
op == UserOperation.PurgeComment ||
op == UserOperation.PurgeCommunity
) {
- let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+ let data = wsJsonToRes<PurgeItemResponse>(msg);
if (data.success) {
toast(i18n.t("purge_success"));
this.context.router.history.push(`/`);
-import { None } from "@sniptt/monads";
import { Component } from "inferno";
import { GetSiteResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
export class Instances extends Component<any, InstancesState> {
private isoData = setIsoData(this.context);
- private emptyState: InstancesState = {
+ state: InstancesState = {
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
get documentTitle(): string {
}
render() {
- return this.state.siteRes.federated_instances.match({
- some: federated_instances => (
- <div className="container-lg">
- <HtmlTags
- title={this.documentTitle}
- path={this.context.router.route.match.url}
- description={None}
- image={None}
- />
- <div className="row">
- <div className="col-md-6">
- <h5>{i18n.t("linked_instances")}</h5>
- {this.itemList(federated_instances.linked)}
- </div>
- {federated_instances.allowed.match({
- some: allowed =>
- allowed.length > 0 && (
- <div className="col-md-6">
- <h5>{i18n.t("allowed_instances")}</h5>
- {this.itemList(allowed)}
- </div>
- ),
- none: <></>,
- })}
- {federated_instances.blocked.match({
- some: blocked =>
- blocked.length > 0 && (
- <div className="col-md-6">
- <h5>{i18n.t("blocked_instances")}</h5>
- {this.itemList(blocked)}
- </div>
- ),
- none: <></>,
- })}
+ let federated_instances = this.state.siteRes.federated_instances;
+ return federated_instances ? (
+ <div className="container-lg">
+ <HtmlTags
+ title={this.documentTitle}
+ path={this.context.router.route.match.url}
+ />
+ <div className="row">
+ <div className="col-md-6">
+ <h5>{i18n.t("linked_instances")}</h5>
+ {this.itemList(federated_instances.linked)}
</div>
+ {federated_instances.allowed &&
+ federated_instances.allowed.length > 0 && (
+ <div className="col-md-6">
+ <h5>{i18n.t("allowed_instances")}</h5>
+ {this.itemList(federated_instances.allowed)}
+ </div>
+ )}
+ {federated_instances.blocked &&
+ federated_instances.blocked.length > 0 && (
+ <div className="col-md-6">
+ <h5>{i18n.t("blocked_instances")}</h5>
+ {this.itemList(federated_instances.blocked)}
+ </div>
+ )}
</div>
- ),
- none: <></>,
- });
+ </div>
+ ) : (
+ <></>
+ );
}
itemList(items: string[]) {
-import { None } from "@sniptt/monads";
import { Component } from "inferno";
import { GetSiteResponse } from "lemmy-js-client";
import { i18n } from "../../i18next";
export class Legal extends Component<any, LegalState> {
private isoData = setIsoData(this.context);
- private emptyState: LegalState = {
+ state: LegalState = {
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
get documentTitle(): string {
}
render() {
+ let legal = this.state.siteRes.site_view.local_site.legal_information;
return (
<div className="container-lg">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
- {this.state.siteRes.site_view.local_site.legal_information.match({
- some: legal => (
- <div className="md-div" dangerouslySetInnerHTML={mdToHtml(legal)} />
- ),
- none: <></>,
- })}
+ {legal && (
+ <div className="md-div" dangerouslySetInnerHTML={mdToHtml(legal)} />
+ )}
</div>
);
}
-import { None } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
GetSiteResponse,
- Login as LoginForm,
+ Login as LoginI,
LoginResponse,
PasswordReset,
UserOperation,
import { Spinner } from "../common/icon";
interface State {
- loginForm: LoginForm;
+ form: {
+ username_or_email?: string;
+ password?: string;
+ };
loginLoading: boolean;
siteRes: GetSiteResponse;
}
export class Login extends Component<any, State> {
private isoData = setIsoData(this.context);
- private subscription: Subscription;
+ private subscription?: Subscription;
- emptyState: State = {
- loginForm: new LoginForm({
- username_or_email: undefined,
- password: undefined,
- }),
+ state: State = {
+ form: {},
loginLoading: false,
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
componentDidMount() {
// Navigate to home if already logged in
- if (UserService.Instance.myUserInfo.isSome()) {
+ if (UserService.Instance.myUserInfo) {
this.context.router.history.push("/");
}
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3">{this.loginForm()}</div>
type="text"
className="form-control"
id="login-email-or-username"
- value={this.state.loginForm.username_or_email}
+ value={this.state.form.username_or_email}
onInput={linkEvent(this, this.handleLoginUsernameChange)}
autoComplete="email"
required
<input
type="password"
id="login-password"
- value={this.state.loginForm.password}
+ value={this.state.form.password}
onInput={linkEvent(this, this.handleLoginPasswordChange)}
className="form-control"
autoComplete="current-password"
type="button"
onClick={linkEvent(this, this.handlePasswordReset)}
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events not-allowed"
- disabled={!validEmail(this.state.loginForm.username_or_email)}
+ disabled={
+ !!this.state.form.username_or_email &&
+ !validEmail(this.state.form.username_or_email)
+ }
title={i18n.t("no_password_reset")}
>
{i18n.t("forgot_password")}
handleLoginSubmit(i: Login, event: any) {
event.preventDefault();
i.setState({ loginLoading: true });
- WebSocketService.Instance.send(wsClient.login(i.state.loginForm));
+ let lForm = i.state.form;
+ let username_or_email = lForm.username_or_email;
+ let password = lForm.password;
+ if (username_or_email && password) {
+ let form: LoginI = {
+ username_or_email,
+ password,
+ };
+ WebSocketService.Instance.send(wsClient.login(form));
+ }
}
handleLoginUsernameChange(i: Login, event: any) {
- i.state.loginForm.username_or_email = event.target.value;
+ i.state.form.username_or_email = event.target.value;
i.setState(i.state);
}
handleLoginPasswordChange(i: Login, event: any) {
- i.state.loginForm.password = event.target.value;
+ i.state.form.password = event.target.value;
i.setState(i.state);
}
handlePasswordReset(i: Login, event: any) {
event.preventDefault();
- let resetForm = new PasswordReset({
- email: i.state.loginForm.username_or_email,
- });
- WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
+ let email = i.state.form.username_or_email;
+ if (email) {
+ let resetForm: PasswordReset = { email };
+ WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
+ }
}
parseMessage(msg: any) {
console.log(msg);
if (msg.error) {
toast(i18n.t(msg.error), "danger");
- this.setState(this.emptyState);
+ this.setState({ form: {} });
return;
} else {
if (op == UserOperation.Login) {
- let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
- this.setState(this.emptyState);
+ let data = wsJsonToRes<LoginResponse>(msg);
UserService.Instance.login(data);
this.props.history.push("/");
location.reload();
} else if (op == UserOperation.PasswordReset) {
toast(i18n.t("reset_password_mail_sent"));
} else if (op == UserOperation.GetSite) {
- let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+ let data = wsJsonToRes<GetSiteResponse>(msg);
this.setState({ siteRes: data });
}
}
-import { None, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Helmet } from "inferno-helmet";
import {
GetSiteResponse,
LoginResponse,
Register,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
import { SiteForm } from "./site-form";
interface State {
- userForm: Register;
+ form: {
+ username?: string;
+ email?: string;
+ password?: string;
+ password_verify?: string;
+ show_nsfw: boolean;
+ captcha_uuid?: string;
+ captcha_answer?: string;
+ honeypot?: string;
+ answer?: string;
+ };
doneRegisteringUser: boolean;
userLoading: boolean;
siteRes: GetSiteResponse;
private subscription: Subscription;
private isoData = setIsoData(this.context);
- private emptyState: State = {
- userForm: new Register({
- username: undefined,
- password: undefined,
- password_verify: undefined,
+ state: State = {
+ form: {
show_nsfw: true,
- // The first admin signup doesn't need a captcha
- captcha_uuid: None,
- captcha_answer: None,
- email: None,
- honeypot: None,
- answer: None,
- }),
- doneRegisteringUser: UserService.Instance.myUserInfo.isSome(),
+ },
+ doneRegisteringUser: !!UserService.Instance.myUserInfo,
userLoading: false,
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.subscription = WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
.subscribe(
type="text"
className="form-control"
id="username"
- value={this.state.userForm.username}
+ value={this.state.form.username}
onInput={linkEvent(this, this.handleRegisterUsernameChange)}
required
minLength={3}
id="email"
className="form-control"
placeholder={i18n.t("optional")}
- value={toUndefined(this.state.userForm.email)}
+ value={this.state.form.email}
onInput={linkEvent(this, this.handleRegisterEmailChange)}
minLength={3}
/>
<input
type="password"
id="password"
- value={this.state.userForm.password}
+ value={this.state.form.password}
onInput={linkEvent(this, this.handleRegisterPasswordChange)}
className="form-control"
required
<input
type="password"
id="verify-password"
- value={this.state.userForm.password_verify}
+ value={this.state.form.password_verify}
onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
className="form-control"
required
event.preventDefault();
i.setState({ userLoading: true });
event.preventDefault();
- WebSocketService.Instance.send(wsClient.register(i.state.userForm));
+ let cForm = i.state.form;
+ if (cForm.username && cForm.password && cForm.password_verify) {
+ let form: Register = {
+ username: cForm.username,
+ password: cForm.password,
+ password_verify: cForm.password_verify,
+ email: cForm.email,
+ show_nsfw: cForm.show_nsfw,
+ captcha_uuid: cForm.captcha_uuid,
+ captcha_answer: cForm.captcha_answer,
+ honeypot: cForm.honeypot,
+ answer: cForm.answer,
+ };
+ WebSocketService.Instance.send(wsClient.register(form));
+ }
}
handleRegisterUsernameChange(i: Setup, event: any) {
- i.state.userForm.username = event.target.value;
+ i.state.form.username = event.target.value;
i.setState(i.state);
}
handleRegisterEmailChange(i: Setup, event: any) {
- i.state.userForm.email = Some(event.target.value);
+ i.state.form.email = event.target.value;
i.setState(i.state);
}
handleRegisterPasswordChange(i: Setup, event: any) {
- i.state.userForm.password = event.target.value;
+ i.state.form.password = event.target.value;
i.setState(i.state);
}
handleRegisterPasswordVerifyChange(i: Setup, event: any) {
- i.state.userForm.password_verify = event.target.value;
+ i.state.form.password_verify = event.target.value;
i.setState(i.state);
}
this.setState({ userLoading: false });
return;
} else if (op == UserOperation.Register) {
- let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
+ let data = wsJsonToRes<LoginResponse>(msg);
this.setState({ userLoading: false });
UserService.Instance.login(data);
- if (UserService.Instance.jwtInfo.isSome()) {
+ if (UserService.Instance.jwtInfo) {
this.setState({ doneRegisteringUser: true });
}
} else if (op == UserOperation.CreateSite) {
-import { None, Option, Some } from "@sniptt/monads";
import { Options, passwordStrength } from "check-password-strength";
import { I18nKeys } from "i18next";
import { Component, linkEvent } from "inferno";
GetSiteResponse,
LoginResponse,
Register,
+ RegistrationMode,
SiteView,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
];
interface State {
- registerForm: Register;
+ form: {
+ username?: string;
+ email?: string;
+ password?: string;
+ password_verify?: string;
+ show_nsfw: boolean;
+ captcha_uuid?: string;
+ captcha_answer?: string;
+ honeypot?: string;
+ answer?: string;
+ };
registerLoading: boolean;
- captcha: Option<GetCaptchaResponse>;
+ captcha?: GetCaptchaResponse;
captchaPlaying: boolean;
siteRes: GetSiteResponse;
}
export class Signup extends Component<any, State> {
private isoData = setIsoData(this.context);
- private subscription: Subscription;
- private audio: HTMLAudioElement;
-
- emptyState: State = {
- registerForm: new Register({
- username: undefined,
- password: undefined,
- password_verify: undefined,
+ private subscription?: Subscription;
+ private audio?: HTMLAudioElement;
+
+ state: State = {
+ form: {
show_nsfw: false,
- captcha_uuid: None,
- captcha_answer: None,
- honeypot: None,
- answer: None,
- email: None,
- }),
+ },
registerLoading: false,
- captcha: None,
captchaPlaying: false,
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleAnswerChange = this.handleAnswerChange.bind(this);
this.parseMessage = this.parseMessage.bind(this);
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3">
type="text"
id="register-username"
className="form-control"
- value={this.state.registerForm.username}
+ value={this.state.form.username}
onInput={linkEvent(this, this.handleRegisterUsernameChange)}
required
minLength={3}
? i18n.t("required")
: i18n.t("optional")
}
- value={toUndefined(this.state.registerForm.email)}
+ value={this.state.form.email}
autoComplete="email"
onInput={linkEvent(this, this.handleRegisterEmailChange)}
required={siteView.local_site.require_email_verification}
minLength={3}
/>
{!siteView.local_site.require_email_verification &&
- !this.state.registerForm.email.map(validEmail).unwrapOr(true) && (
+ this.state.form.email &&
+ !validEmail(this.state.form.email) && (
<div className="mt-2 mb-0 alert alert-warning" role="alert">
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
{i18n.t("no_password_reset")}
<input
type="password"
id="register-password"
- value={this.state.registerForm.password}
+ value={this.state.form.password}
autoComplete="new-password"
onInput={linkEvent(this, this.handleRegisterPasswordChange)}
minLength={10}
className="form-control"
required
/>
- {this.state.registerForm.password && (
+ {this.state.form.password && (
<div className={this.passwordColorClass}>
{i18n.t(this.passwordStrength as I18nKeys)}
</div>
<input
type="password"
id="register-verify-password"
- value={this.state.registerForm.password_verify}
+ value={this.state.form.password_verify}
autoComplete="new-password"
onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
maxLength={60}
</div>
</div>
- {siteView.local_site.require_application && (
+ {siteView.local_site.registration_mode ==
+ RegistrationMode.RequireApplication && (
<>
<div className="form-group row">
<div className="offset-sm-2 col-sm-10">
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
{i18n.t("fill_out_application")}
</div>
- {siteView.local_site.application_question.match({
- some: question => (
- <div
- className="md-div"
- dangerouslySetInnerHTML={mdToHtml(question)}
- />
- ),
- none: <></>,
- })}
+ {siteView.local_site.application_question && (
+ <div
+ className="md-div"
+ dangerouslySetInnerHTML={mdToHtml(
+ siteView.local_site.application_question
+ )}
+ />
+ )}
</div>
</div>
</label>
<div className="col-sm-10">
<MarkdownTextArea
- initialContent={None}
- initialLanguageId={None}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
onContentChange={this.handleAnswerChange}
hideNavigationWarnings
allLanguages={[]}
</>
)}
- {this.state.captcha.isSome() && (
+ {this.state.captcha && (
<div className="form-group row">
<label className="col-sm-2" htmlFor="register-captcha">
<span className="mr-2">{i18n.t("enter_code")}</span>
type="text"
className="form-control"
id="register-captcha"
- value={toUndefined(this.state.registerForm.captcha_answer)}
+ value={this.state.form.captcha_answer}
onInput={linkEvent(
this,
this.handleRegisterCaptchaAnswerChange
className="form-check-input"
id="register-show-nsfw"
type="checkbox"
- checked={this.state.registerForm.show_nsfw}
+ checked={this.state.form.show_nsfw}
onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
/>
<label
type="text"
className="form-control honeypot"
id="register-honey"
- value={toUndefined(this.state.registerForm.honeypot)}
+ value={this.state.form.honeypot}
onInput={linkEvent(this, this.handleHoneyPotChange)}
/>
<div className="form-group row">
}
showCaptcha() {
- return this.state.captcha.match({
- some: captcha => (
- <div className="col-sm-4">
- {captcha.ok.match({
- some: res => (
- <>
- <img
- className="rounded-top img-fluid"
- src={this.captchaPngSrc(res)}
- style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
- alt={i18n.t("captcha")}
- />
- {res.wav.isSome() && (
- <button
- className="rounded-bottom btn btn-sm btn-secondary btn-block"
- style="border-top-right-radius: 0; border-top-left-radius: 0;"
- title={i18n.t("play_captcha_audio")}
- onClick={linkEvent(this, this.handleCaptchaPlay)}
- type="button"
- disabled={this.state.captchaPlaying}
- >
- <Icon icon="play" classes="icon-play" />
- </button>
- )}
- </>
- ),
- none: <></>,
- })}
- </div>
- ),
- none: <></>,
- });
+ let captchaRes = this.state.captcha?.ok;
+ return captchaRes ? (
+ <div className="col-sm-4">
+ <>
+ <img
+ className="rounded-top img-fluid"
+ src={this.captchaPngSrc(captchaRes)}
+ style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
+ alt={i18n.t("captcha")}
+ />
+ {captchaRes.wav && (
+ <button
+ className="rounded-bottom btn btn-sm btn-secondary btn-block"
+ style="border-top-right-radius: 0; border-top-left-radius: 0;"
+ title={i18n.t("play_captcha_audio")}
+ onClick={linkEvent(this, this.handleCaptchaPlay)}
+ type="button"
+ disabled={this.state.captchaPlaying}
+ >
+ <Icon icon="play" classes="icon-play" />
+ </button>
+ )}
+ </>
+ </div>
+ ) : (
+ <></>
+ );
}
- get passwordStrength() {
- return passwordStrength(
- this.state.registerForm.password,
- passwordStrengthOptions
- ).value;
+ get passwordStrength(): string | undefined {
+ let password = this.state.form.password;
+ return password
+ ? passwordStrength(password, passwordStrengthOptions).value
+ : undefined;
}
get passwordColorClass(): string {
let strength = this.passwordStrength;
- if (["weak", "medium"].includes(strength)) {
+ if (strength && ["weak", "medium"].includes(strength)) {
return "text-warning";
} else if (strength == "strong") {
return "text-success";
handleRegisterSubmit(i: Signup, event: any) {
event.preventDefault();
i.setState({ registerLoading: true });
- WebSocketService.Instance.send(wsClient.register(i.state.registerForm));
+ let cForm = i.state.form;
+ if (cForm.username && cForm.password && cForm.password_verify) {
+ let form: Register = {
+ username: cForm.username,
+ password: cForm.password,
+ password_verify: cForm.password_verify,
+ email: cForm.email,
+ show_nsfw: cForm.show_nsfw,
+ captcha_uuid: cForm.captcha_uuid,
+ captcha_answer: cForm.captcha_answer,
+ honeypot: cForm.honeypot,
+ answer: cForm.answer,
+ };
+ WebSocketService.Instance.send(wsClient.register(form));
+ }
}
handleRegisterUsernameChange(i: Signup, event: any) {
- i.state.registerForm.username = event.target.value;
+ i.state.form.username = event.target.value;
i.setState(i.state);
}
handleRegisterEmailChange(i: Signup, event: any) {
- i.state.registerForm.email = Some(event.target.value);
- if (i.state.registerForm.email.unwrap() == "") {
- i.state.registerForm.email = None;
+ i.state.form.email = event.target.value;
+ if (i.state.form.email == "") {
+ i.state.form.email = undefined;
}
i.setState(i.state);
}
handleRegisterPasswordChange(i: Signup, event: any) {
- i.state.registerForm.password = event.target.value;
+ i.state.form.password = event.target.value;
i.setState(i.state);
}
handleRegisterPasswordVerifyChange(i: Signup, event: any) {
- i.state.registerForm.password_verify = event.target.value;
+ i.state.form.password_verify = event.target.value;
i.setState(i.state);
}
handleRegisterShowNsfwChange(i: Signup, event: any) {
- i.state.registerForm.show_nsfw = event.target.checked;
+ i.state.form.show_nsfw = event.target.checked;
i.setState(i.state);
}
handleRegisterCaptchaAnswerChange(i: Signup, event: any) {
- i.state.registerForm.captcha_answer = Some(event.target.value);
+ i.state.form.captcha_answer = event.target.value;
i.setState(i.state);
}
handleAnswerChange(val: string) {
- this.setState(s => ((s.registerForm.answer = Some(val)), s));
+ this.setState(s => ((s.form.answer = val), s));
}
handleHoneyPotChange(i: Signup, event: any) {
- i.state.registerForm.honeypot = Some(event.target.value);
+ i.state.form.honeypot = event.target.value;
i.setState(i.state);
}
handleRegenCaptcha(i: Signup) {
- i.audio = null;
+ i.audio = undefined;
i.setState({ captchaPlaying: false });
WebSocketService.Instance.send(wsClient.getCaptcha());
}
handleCaptchaPlay(i: Signup) {
// This was a bad bug, it should only build the new audio on a new file.
// Replays would stop prematurely if this was rebuilt every time.
- i.state.captcha.match({
- some: captcha =>
- captcha.ok.match({
- some: res => {
- if (i.audio == null) {
- let base64 = `data:audio/wav;base64,${res.wav}`;
- i.audio = new Audio(base64);
- }
-
- i.audio.play();
-
- i.setState({ captchaPlaying: true });
-
- i.audio.addEventListener("ended", () => {
- i.audio.currentTime = 0;
- i.setState({ captchaPlaying: false });
- });
- },
- none: void 0,
- }),
- none: void 0,
- });
+ let captchaRes = i.state.captcha?.ok;
+ if (captchaRes) {
+ if (!i.audio) {
+ let base64 = `data:audio/wav;base64,${captchaRes.wav}`;
+ i.audio = new Audio(base64);
+ i.audio.play();
+
+ i.setState({ captchaPlaying: true });
+
+ i.audio.addEventListener("ended", () => {
+ if (i.audio) {
+ i.audio.currentTime = 0;
+ i.setState({ captchaPlaying: false });
+ }
+ });
+ }
+ }
}
captchaPngSrc(captcha: CaptchaResponse) {
console.log(msg);
if (msg.error) {
toast(i18n.t(msg.error), "danger");
- this.setState(this.emptyState);
- this.setState(s => ((s.registerForm.captcha_answer = undefined), s));
+ this.setState(s => ((s.form.captcha_answer = undefined), s));
// Refetch another captcha
// WebSocketService.Instance.send(wsClient.getCaptcha());
return;
} else {
if (op == UserOperation.Register) {
- let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
- this.setState(this.emptyState);
+ let data = wsJsonToRes<LoginResponse>(msg);
// Only log them in if a jwt was set
- if (data.jwt.isSome()) {
+ if (data.jwt) {
UserService.Instance.login(data);
this.props.history.push("/communities");
location.reload();
this.props.history.push("/");
}
} else if (op == UserOperation.GetCaptcha) {
- let data = wsJsonToRes<GetCaptchaResponse>(msg, GetCaptchaResponse);
- data.ok.match({
- some: res => {
- this.setState({ captcha: Some(data) });
- this.setState(
- s => ((s.registerForm.captcha_uuid = Some(res.uuid)), s)
- );
- },
- none: void 0,
- });
+ let data = wsJsonToRes<GetCaptchaResponse>(msg);
+ if (data.ok) {
+ this.setState({ captcha: data });
+ this.setState(s => ((s.form.captcha_uuid = data.ok?.uuid), s));
+ }
} else if (op == UserOperation.PasswordReset) {
toast(i18n.t("reset_password_mail_sent"));
} else if (op == UserOperation.GetSite) {
- let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+ let data = wsJsonToRes<GetSiteResponse>(msg);
this.setState({ siteRes: data });
}
}
-import { None, Option, Some } from "@sniptt/monads";
import { Component, InfernoMouseEvent, linkEvent } from "inferno";
import { Prompt } from "inferno-router";
import {
EditSite,
GetSiteResponse,
ListingType,
- toUndefined,
+ RegistrationMode,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
import {
- auth,
capitalizeFirstLetter,
fetchThemeList,
+ myAuth,
wsClient,
} from "../../utils";
import { Icon, Spinner } from "../common/icon";
interface SiteFormState {
siteForm: EditSite;
loading: boolean;
- themeList: Option<string[]>;
+ themeList?: string[];
}
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
- private emptyState: SiteFormState = {
- siteForm: new EditSite({
- enable_downvotes: None,
- open_registration: None,
- enable_nsfw: None,
- name: None,
- icon: None,
- banner: None,
- require_email_verification: None,
- require_application: None,
- application_question: None,
- private_instance: None,
- default_theme: None,
- sidebar: None,
- default_post_listing_type: None,
- legal_information: None,
- description: None,
- community_creation_admin_only: None,
- application_email_admins: None,
- hide_modlog_mod_names: None,
- discussion_languages: None,
- slur_filter_regex: None,
- actor_name_max_length: None,
- rate_limit_message: None,
- rate_limit_message_per_second: None,
- rate_limit_comment: None,
- rate_limit_comment_per_second: None,
- rate_limit_image: None,
- rate_limit_image_per_second: None,
- rate_limit_post: None,
- rate_limit_post_per_second: None,
- rate_limit_register: None,
- rate_limit_register_per_second: None,
- rate_limit_search: None,
- rate_limit_search_per_second: None,
- federation_enabled: None,
- federation_debug: None,
- federation_worker_count: None,
- captcha_enabled: None,
- captcha_difficulty: None,
- allowed_instances: None,
- blocked_instances: None,
- taglines: None,
- auth: undefined,
- }),
+ state: SiteFormState = {
+ siteForm: {
+ auth: "TODO",
+ },
loading: false,
- themeList: None,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
this.handleSiteLegalInfoChange = this.handleSiteLegalInfoChange.bind(this);
this.handleSiteApplicationQuestionChange =
let lsrl = this.props.siteRes.site_view.local_site_rate_limit;
this.state = {
...this.state,
- siteForm: new EditSite({
- name: Some(site.name),
+ siteForm: {
+ name: site.name,
sidebar: site.sidebar,
description: site.description,
- enable_downvotes: Some(ls.enable_downvotes),
- open_registration: Some(ls.open_registration),
- enable_nsfw: Some(ls.enable_nsfw),
- community_creation_admin_only: Some(ls.community_creation_admin_only),
+ enable_downvotes: ls.enable_downvotes,
+ registration_mode: ls.registration_mode,
+ enable_nsfw: ls.enable_nsfw,
+ community_creation_admin_only: ls.community_creation_admin_only,
icon: site.icon,
banner: site.banner,
- require_email_verification: Some(ls.require_email_verification),
- require_application: Some(ls.require_application),
+ require_email_verification: ls.require_email_verification,
application_question: ls.application_question,
- private_instance: Some(ls.private_instance),
- default_theme: Some(ls.default_theme),
- default_post_listing_type: Some(ls.default_post_listing_type),
+ private_instance: ls.private_instance,
+ default_theme: ls.default_theme,
+ default_post_listing_type: ls.default_post_listing_type,
legal_information: ls.legal_information,
- application_email_admins: Some(ls.application_email_admins),
- hide_modlog_mod_names: Some(ls.hide_modlog_mod_names),
- discussion_languages: Some(this.props.siteRes.discussion_languages),
+ application_email_admins: ls.application_email_admins,
+ hide_modlog_mod_names: ls.hide_modlog_mod_names,
+ discussion_languages: this.props.siteRes.discussion_languages,
slur_filter_regex: ls.slur_filter_regex,
- actor_name_max_length: Some(ls.actor_name_max_length),
- rate_limit_message: Some(lsrl.message),
- rate_limit_message_per_second: Some(lsrl.message_per_second),
- rate_limit_comment: Some(lsrl.comment),
- rate_limit_comment_per_second: Some(lsrl.comment_per_second),
- rate_limit_image: Some(lsrl.image),
- rate_limit_image_per_second: Some(lsrl.image_per_second),
- rate_limit_post: Some(lsrl.post),
- rate_limit_post_per_second: Some(lsrl.post_per_second),
- rate_limit_register: Some(lsrl.register),
- rate_limit_register_per_second: Some(lsrl.register_per_second),
- rate_limit_search: Some(lsrl.search),
- rate_limit_search_per_second: Some(lsrl.search_per_second),
- federation_enabled: Some(ls.federation_enabled),
- federation_debug: Some(ls.federation_debug),
- federation_worker_count: Some(ls.federation_worker_count),
- captcha_enabled: Some(ls.captcha_enabled),
- captcha_difficulty: Some(ls.captcha_difficulty),
- allowed_instances: this.props.siteRes.federated_instances.andThen(
- f => f.allowed
- ),
- blocked_instances: this.props.siteRes.federated_instances.andThen(
- f => f.blocked
- ),
- taglines: this.props.siteRes.taglines.map(x => x.map(y => y.content)),
- auth: undefined,
- }),
+ actor_name_max_length: ls.actor_name_max_length,
+ rate_limit_message: lsrl.message,
+ rate_limit_message_per_second: lsrl.message_per_second,
+ rate_limit_comment: lsrl.comment,
+ rate_limit_comment_per_second: lsrl.comment_per_second,
+ rate_limit_image: lsrl.image,
+ rate_limit_image_per_second: lsrl.image_per_second,
+ rate_limit_post: lsrl.post,
+ rate_limit_post_per_second: lsrl.post_per_second,
+ rate_limit_register: lsrl.register,
+ rate_limit_register_per_second: lsrl.register_per_second,
+ rate_limit_search: lsrl.search,
+ rate_limit_search_per_second: lsrl.search_per_second,
+ federation_enabled: ls.federation_enabled,
+ federation_debug: ls.federation_debug,
+ federation_worker_count: ls.federation_worker_count,
+ captcha_enabled: ls.captcha_enabled,
+ captcha_difficulty: ls.captcha_difficulty,
+ allowed_instances: this.props.siteRes.federated_instances?.allowed,
+ blocked_instances: this.props.siteRes.federated_instances?.blocked,
+ taglines: this.props.siteRes.taglines?.map(x => x.content),
+ auth: "TODO",
+ },
};
}
async componentDidMount() {
- this.setState({ themeList: Some(await fetchThemeList()) });
+ this.setState({ themeList: await fetchThemeList() });
}
// Necessary to stop the loading
) {
window.onbeforeunload = () => true;
} else {
- window.onbeforeunload = undefined;
+ window.onbeforeunload = null;
}
}
type="text"
id="create-site-name"
className="form-control"
- value={toUndefined(this.state.siteForm.name)}
+ value={this.state.siteForm.name}
onInput={linkEvent(this, this.handleSiteNameChange)}
required
minLength={3}
type="text"
className="form-control"
id="site-desc"
- value={toUndefined(this.state.siteForm.description)}
+ value={this.state.siteForm.description}
onInput={linkEvent(this, this.handleSiteDescChange)}
maxLength={150}
/>
<div className="col-12">
<MarkdownTextArea
initialContent={this.state.siteForm.sidebar}
- initialLanguageId={None}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
onContentChange={this.handleSiteSidebarChange}
hideNavigationWarnings
allLanguages={[]}
<div className="col-12">
<MarkdownTextArea
initialContent={this.state.siteForm.legal_information}
- initialLanguageId={None}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
onContentChange={this.handleSiteLegalInfoChange}
hideNavigationWarnings
allLanguages={[]}
/>
</div>
</div>
- {this.state.siteForm.require_application.unwrapOr(false) && (
- <div className="form-group row">
- <label className="col-12 col-form-label">
- {i18n.t("application_questionnaire")}
- </label>
- <div className="col-12">
- <MarkdownTextArea
- initialContent={this.state.siteForm.application_question}
- initialLanguageId={None}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
- onContentChange={this.handleSiteApplicationQuestionChange}
- hideNavigationWarnings
- allLanguages={[]}
- siteLanguages={[]}
- />
- </div>
- </div>
- )}
<div className="form-group row">
<div className="col-12">
<div className="form-check">
className="form-check-input"
id="create-site-downvotes"
type="checkbox"
- checked={toUndefined(this.state.siteForm.enable_downvotes)}
+ checked={this.state.siteForm.enable_downvotes}
onChange={linkEvent(
this,
this.handleSiteEnableDownvotesChange
className="form-check-input"
id="create-site-enable-nsfw"
type="checkbox"
- checked={toUndefined(this.state.siteForm.enable_nsfw)}
+ checked={this.state.siteForm.enable_nsfw}
onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
/>
<label
</div>
<div className="form-group row">
<div className="col-12">
- <div className="form-check">
- <input
- className="form-check-input"
- id="create-site-open-registration"
- type="checkbox"
- checked={toUndefined(this.state.siteForm.open_registration)}
- onChange={linkEvent(
- this,
- this.handleSiteOpenRegistrationChange
- )}
- />
- <label
- className="form-check-label"
- htmlFor="create-site-open-registration"
- >
+ <label
+ className="form-check-label mr-2"
+ htmlFor="create-site-registration-mode"
+ >
+ {i18n.t("registration_mode")}
+ </label>
+ <select
+ id="create-site-registration-mode"
+ value={this.state.siteForm.registration_mode}
+ onChange={linkEvent(
+ this,
+ this.handleSiteRegistrationModeChange
+ )}
+ className="custom-select w-auto"
+ >
+ <option value={RegistrationMode.RequireApplication}>
+ {i18n.t("require_registration_application")}
+ </option>
+ <option value={RegistrationMode.Open}>
{i18n.t("open_registration")}
- </label>
- </div>
+ </option>
+ <option value={RegistrationMode.Closed}>
+ {i18n.t("close_registration")}
+ </option>
+ </select>
</div>
</div>
+ {this.state.siteForm.registration_mode ==
+ RegistrationMode.RequireApplication && (
+ <div className="form-group row">
+ <label className="col-12 col-form-label">
+ {i18n.t("application_questionnaire")}
+ </label>
+ <div className="col-12">
+ <MarkdownTextArea
+ initialContent={this.state.siteForm.application_question}
+ onContentChange={this.handleSiteApplicationQuestionChange}
+ hideNavigationWarnings
+ allLanguages={[]}
+ siteLanguages={[]}
+ />
+ </div>
+ </div>
+ )}
<div className="form-group row">
<div className="col-12">
<div className="form-check">
className="form-check-input"
id="create-site-community-creation-admin-only"
type="checkbox"
- checked={toUndefined(
- this.state.siteForm.community_creation_admin_only
- )}
+ checked={this.state.siteForm.community_creation_admin_only}
onChange={linkEvent(
this,
this.handleSiteCommunityCreationAdminOnly
className="form-check-input"
id="create-site-require-email-verification"
type="checkbox"
- checked={toUndefined(
- this.state.siteForm.require_email_verification
- )}
+ checked={this.state.siteForm.require_email_verification}
onChange={linkEvent(
this,
this.handleSiteRequireEmailVerification
</div>
</div>
</div>
- <div className="form-group row">
- <div className="col-12">
- <div className="form-check">
- <input
- className="form-check-input"
- id="create-site-require-application"
- type="checkbox"
- checked={toUndefined(this.state.siteForm.require_application)}
- onChange={linkEvent(this, this.handleSiteRequireApplication)}
- />
- <label
- className="form-check-label"
- htmlFor="create-site-require-application"
- >
- {i18n.t("require_registration_application")}
- </label>
- </div>
- </div>
- </div>
<div className="form-group row">
<div className="col-12">
<div className="form-check">
className="form-check-input"
id="create-site-application-email-admins"
type="checkbox"
- checked={toUndefined(
- this.state.siteForm.application_email_admins
- )}
+ checked={this.state.siteForm.application_email_admins}
onChange={linkEvent(
this,
this.handleSiteApplicationEmailAdmins
</label>
<select
id="create-site-default-theme"
- value={toUndefined(this.state.siteForm.default_theme)}
+ value={this.state.siteForm.default_theme}
onChange={linkEvent(this, this.handleSiteDefaultTheme)}
className="custom-select w-auto"
>
<option value="browser">{i18n.t("browser_default")}</option>
- {this.state.themeList.unwrapOr([]).map(theme => (
+ {this.state.themeList?.map(theme => (
<option key={theme} value={theme}>
{theme}
</option>
<ListingTypeSelect
type_={
ListingType[
- this.state.siteForm.default_post_listing_type.unwrapOr(
- "Local"
- )
+ this.state.siteForm.default_post_listing_type ?? "Local"
]
}
showLocal
className="form-check-input"
id="create-site-private-instance"
type="checkbox"
- checked={toUndefined(this.state.siteForm.private_instance)}
+ checked={this.state.siteForm.private_instance}
onChange={linkEvent(this, this.handleSitePrivateInstance)}
/>
<label
className="form-check-input"
id="create-site-hide-modlog-mod-names"
type="checkbox"
- checked={toUndefined(
- this.state.siteForm.hide_modlog_mod_names
- )}
+ checked={this.state.siteForm.hide_modlog_mod_names}
onChange={linkEvent(this, this.handleSiteHideModlogModNames)}
/>
<label
id="create-site-slur-filter-regex"
placeholder="(word1|word2)"
className="form-control"
- value={toUndefined(this.state.siteForm.slur_filter_regex)}
+ value={this.state.siteForm.slur_filter_regex}
onInput={linkEvent(this, this.handleSiteSlurFilterRegex)}
minLength={3}
/>
id="create-site-actor-name"
className="form-control"
min={5}
- value={toUndefined(this.state.siteForm.actor_name_max_length)}
+ value={this.state.siteForm.actor_name_max_length}
onInput={linkEvent(this, this.handleSiteActorNameMaxLength)}
/>
</div>
className="form-check-input"
id="create-site-federation-enabled"
type="checkbox"
- checked={toUndefined(this.state.siteForm.federation_enabled)}
+ checked={this.state.siteForm.federation_enabled}
onChange={linkEvent(this, this.handleSiteFederationEnabled)}
/>
<label
</div>
</div>
</div>
- {this.state.siteForm.federation_enabled.unwrapOr(false) && (
+ {this.state.siteForm.federation_enabled && (
<>
<div className="form-group row">
<label
className="form-check-input"
id="create-site-federation-debug"
type="checkbox"
- checked={toUndefined(
- this.state.siteForm.federation_debug
- )}
+ checked={this.state.siteForm.federation_debug}
onChange={linkEvent(this, this.handleSiteFederationDebug)}
/>
<label
id="create-site-federation-worker-count"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.federation_worker_count
- )}
+ value={this.state.siteForm.federation_worker_count}
onInput={linkEvent(
this,
this.handleSiteFederationWorkerCount
className="form-check-input"
id="create-site-captcha-enabled"
type="checkbox"
- checked={toUndefined(this.state.siteForm.captcha_enabled)}
+ checked={this.state.siteForm.captcha_enabled}
onChange={linkEvent(this, this.handleSiteCaptchaEnabled)}
/>
<label
</div>
</div>
</div>
- {this.state.siteForm.captcha_enabled.unwrapOr(false) && (
+ {this.state.siteForm.captcha_enabled && (
<div className="form-group row">
<div className="col-12">
<label
</label>
<select
id="create-site-captcha-difficulty"
- value={toUndefined(this.state.siteForm.captcha_difficulty)}
+ value={this.state.siteForm.captcha_difficulty}
onChange={linkEvent(this, this.handleSiteCaptchaDifficulty)}
className="custom-select w-auto"
>
id="create-site-rate-limit-message"
className="form-control"
min={0}
- value={toUndefined(this.state.siteForm.rate_limit_message)}
+ value={this.state.siteForm.rate_limit_message}
onInput={linkEvent(this, this.handleSiteRateLimitMessage)}
/>
</div>
id="create-site-rate-limit-message-per-second"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.rate_limit_message_per_second
- )}
+ value={this.state.siteForm.rate_limit_message_per_second}
onInput={linkEvent(
this,
this.handleSiteRateLimitMessagePerSecond
id="create-site-rate-limit-post"
className="form-control"
min={0}
- value={toUndefined(this.state.siteForm.rate_limit_post)}
+ value={this.state.siteForm.rate_limit_post}
onInput={linkEvent(this, this.handleSiteRateLimitPost)}
/>
</div>
id="create-site-rate-limit-post-per-second"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.rate_limit_post_per_second
- )}
+ value={this.state.siteForm.rate_limit_post_per_second}
onInput={linkEvent(this, this.handleSiteRateLimitPostPerSecond)}
/>
</div>
id="create-site-rate-limit-register"
className="form-control"
min={0}
- value={toUndefined(this.state.siteForm.rate_limit_register)}
+ value={this.state.siteForm.rate_limit_register}
onInput={linkEvent(this, this.handleSiteRateLimitRegister)}
/>
</div>
id="create-site-rate-limit-register-per-second"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.rate_limit_register_per_second
- )}
+ value={this.state.siteForm.rate_limit_register_per_second}
onInput={linkEvent(
this,
this.handleSiteRateLimitRegisterPerSecond
id="create-site-rate-limit-image"
className="form-control"
min={0}
- value={toUndefined(this.state.siteForm.rate_limit_image)}
+ value={this.state.siteForm.rate_limit_image}
onInput={linkEvent(this, this.handleSiteRateLimitImage)}
/>
</div>
id="create-site-rate-limit-image-per-second"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.rate_limit_image_per_second
- )}
+ value={this.state.siteForm.rate_limit_image_per_second}
onInput={linkEvent(
this,
this.handleSiteRateLimitImagePerSecond
id="create-site-rate-limit-comment"
className="form-control"
min={0}
- value={toUndefined(this.state.siteForm.rate_limit_comment)}
+ value={this.state.siteForm.rate_limit_comment}
onInput={linkEvent(this, this.handleSiteRateLimitComment)}
/>
</div>
id="create-site-rate-limit-comment-per-second"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.rate_limit_comment_per_second
- )}
+ value={this.state.siteForm.rate_limit_comment_per_second}
onInput={linkEvent(
this,
this.handleSiteRateLimitCommentPerSecond
id="create-site-rate-limit-search"
className="form-control"
min={0}
- value={toUndefined(this.state.siteForm.rate_limit_search)}
+ value={this.state.siteForm.rate_limit_search}
onInput={linkEvent(this, this.handleSiteRateLimitSearch)}
/>
</div>
id="create-site-rate-limit-search-per-second"
className="form-control"
min={0}
- value={toUndefined(
- this.state.siteForm.rate_limit_search_per_second
- )}
+ value={this.state.siteForm.rate_limit_search_per_second}
onInput={linkEvent(
this,
this.handleSiteRateLimitSearchPerSecond
<table id="taglines_table" className="table table-sm table-hover">
<thead className="pointer"></thead>
<tbody>
- {this.state.siteForm.taglines
- .unwrapOr([])
- .map((cv, index) => (
- <tr key={index}>
- <td>
- <MarkdownTextArea
- initialContent={Some(cv)}
- initialLanguageId={None}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
- onContentChange={s =>
- this.handleTaglineChange(this, index, s)
- }
- hideNavigationWarnings
- allLanguages={this.props.siteRes.all_languages}
- siteLanguages={
- this.props.siteRes.discussion_languages
- }
+ {this.state.siteForm.taglines?.map((cv, index) => (
+ <tr key={index}>
+ <td>
+ <MarkdownTextArea
+ initialContent={cv}
+ onContentChange={s =>
+ this.handleTaglineChange(this, index, s)
+ }
+ hideNavigationWarnings
+ allLanguages={this.props.siteRes.all_languages}
+ siteLanguages={
+ this.props.siteRes.discussion_languages
+ }
+ />
+ </td>
+ <td className="text-right">
+ <button
+ className="btn btn-link btn-animate text-muted"
+ onClick={e =>
+ this.handleDeleteTaglineClick(this, index, e)
+ }
+ data-tippy-content={i18n.t("delete")}
+ aria-label={i18n.t("delete")}
+ >
+ <Icon
+ icon="trash"
+ classes={`icon-inline text-danger`}
/>
- </td>
- <td className="text-right">
- <button
- className="btn btn-link btn-animate text-muted"
- onClick={e =>
- this.handleDeleteTaglineClick(this, index, e)
- }
- data-tippy-content={i18n.t("delete")}
- aria-label={i18n.t("delete")}
- >
- <Icon
- icon="trash"
- classes={`icon-inline text-danger`}
- />
- </button>
- </td>
- </tr>
- ))}
+ </button>
+ </td>
+ </tr>
+ ))}
</tbody>
</table>
<button
handleCreateSiteSubmit(i: SiteForm, event: any) {
event.preventDefault();
i.setState({ loading: true });
- i.setState(s => ((s.siteForm.auth = auth().unwrap()), s));
+ let auth = myAuth() ?? "TODO";
+ i.setState(s => ((s.siteForm.auth = auth), s));
if (i.props.siteRes.site_view.local_site.site_setup) {
WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
} else {
let sForm = i.state.siteForm;
- let form = new CreateSite({
- name: sForm.name.unwrapOr("My site"),
+ let form: CreateSite = {
+ name: sForm.name ?? "My site",
sidebar: sForm.sidebar,
description: sForm.description,
icon: sForm.icon,
community_creation_admin_only: sForm.community_creation_admin_only,
enable_nsfw: sForm.enable_nsfw,
enable_downvotes: sForm.enable_downvotes,
- require_application: sForm.require_application,
application_question: sForm.application_question,
- open_registration: sForm.open_registration,
+ registration_mode: sForm.registration_mode,
require_email_verification: sForm.require_email_verification,
private_instance: sForm.private_instance,
default_theme: sForm.default_theme,
default_post_listing_type: sForm.default_post_listing_type,
application_email_admins: sForm.application_email_admins,
- auth: auth().unwrap(),
hide_modlog_mod_names: sForm.hide_modlog_mod_names,
legal_information: sForm.legal_information,
slur_filter_regex: sForm.slur_filter_regex,
blocked_instances: sForm.blocked_instances,
discussion_languages: sForm.discussion_languages,
taglines: sForm.taglines,
- });
+ auth,
+ };
WebSocketService.Instance.send(wsClient.createSite(form));
}
i.setState(i.state);
}
- instancesToString(opt: Option<string[]>): string {
- return opt.map(list => list.join(",")).unwrapOr("");
+ instancesToString(opt?: string[]): string {
+ return opt ? opt.join(",") : "";
}
handleSiteAllowedInstances(i: SiteForm, event: any) {
}
handleSiteNameChange(i: SiteForm, event: any) {
- i.state.siteForm.name = Some(event.target.value);
+ i.state.siteForm.name = event.target.value;
i.setState(i.state);
}
handleSiteSidebarChange(val: string) {
- this.setState(s => ((s.siteForm.sidebar = Some(val)), s));
+ this.setState(s => ((s.siteForm.sidebar = val), s));
}
handleSiteLegalInfoChange(val: string) {
- this.setState(s => ((s.siteForm.legal_information = Some(val)), s));
+ this.setState(s => ((s.siteForm.legal_information = val), s));
}
handleTaglineChange(i: SiteForm, index: number, val: string) {
- i.state.siteForm.taglines.match({
- some: tls => {
- tls[index] = val;
- },
- none: void 0,
- });
- i.setState(i.state);
+ let taglines = i.state.siteForm.taglines;
+ if (taglines) {
+ taglines[index] = val;
+ i.setState(i.state);
+ }
}
handleDeleteTaglineClick(
event: InfernoMouseEvent<HTMLButtonElement>
) {
event.preventDefault();
- if (i.state.siteForm.taglines.isSome()) {
- let taglines = i.state.siteForm.taglines.unwrap();
+ let taglines = i.state.siteForm.taglines;
+ if (taglines) {
taglines.splice(index, 1);
- i.state.siteForm.taglines = None; // force rerender of table rows
+ i.state.siteForm.taglines = undefined;
i.setState(i.state);
- i.state.siteForm.taglines = Some(taglines);
+ i.state.siteForm.taglines = taglines;
i.setState(i.state);
}
}
event: InfernoMouseEvent<HTMLButtonElement>
) {
event.preventDefault();
- if (i.state.siteForm.taglines.isNone()) {
- i.state.siteForm.taglines = Some([]);
+ if (!i.state.siteForm.taglines) {
+ i.state.siteForm.taglines = [];
}
- i.state.siteForm.taglines.unwrap().push("");
+ i.state.siteForm.taglines.push("");
i.setState(i.state);
}
handleSiteApplicationQuestionChange(val: string) {
- this.setState(s => ((s.siteForm.application_question = Some(val)), s));
+ this.setState(s => ((s.siteForm.application_question = val), s));
}
handleSiteDescChange(i: SiteForm, event: any) {
- i.state.siteForm.description = Some(event.target.value);
+ i.state.siteForm.description = event.target.value;
i.setState(i.state);
}
handleSiteEnableNsfwChange(i: SiteForm, event: any) {
- i.state.siteForm.enable_nsfw = Some(event.target.checked);
+ i.state.siteForm.enable_nsfw = event.target.checked;
i.setState(i.state);
}
- handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
- i.state.siteForm.open_registration = Some(event.target.checked);
+ handleSiteRegistrationModeChange(i: SiteForm, event: any) {
+ i.state.siteForm.registration_mode = event.target.value;
i.setState(i.state);
}
handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
- i.state.siteForm.community_creation_admin_only = Some(event.target.checked);
+ i.state.siteForm.community_creation_admin_only = event.target.checked;
i.setState(i.state);
}
handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
- i.state.siteForm.enable_downvotes = Some(event.target.checked);
- i.setState(i.state);
- }
-
- handleSiteRequireApplication(i: SiteForm, event: any) {
- i.state.siteForm.require_application = Some(event.target.checked);
+ i.state.siteForm.enable_downvotes = event.target.checked;
i.setState(i.state);
}
handleSiteRequireEmailVerification(i: SiteForm, event: any) {
- i.state.siteForm.require_email_verification = Some(event.target.checked);
+ i.state.siteForm.require_email_verification = event.target.checked;
i.setState(i.state);
}
handleSiteApplicationEmailAdmins(i: SiteForm, event: any) {
- i.state.siteForm.application_email_admins = Some(event.target.checked);
+ i.state.siteForm.application_email_admins = event.target.checked;
i.setState(i.state);
}
handleSitePrivateInstance(i: SiteForm, event: any) {
- i.state.siteForm.private_instance = Some(event.target.checked);
+ i.state.siteForm.private_instance = event.target.checked;
i.setState(i.state);
}
handleSiteHideModlogModNames(i: SiteForm, event: any) {
- i.state.siteForm.hide_modlog_mod_names = Some(event.target.checked);
+ i.state.siteForm.hide_modlog_mod_names = event.target.checked;
i.setState(i.state);
}
handleSiteDefaultTheme(i: SiteForm, event: any) {
- i.state.siteForm.default_theme = Some(event.target.value);
+ i.state.siteForm.default_theme = event.target.value;
i.setState(i.state);
}
handleIconUpload(url: string) {
- this.setState(s => ((s.siteForm.icon = Some(url)), s));
+ this.setState(s => ((s.siteForm.icon = url), s));
}
handleIconRemove() {
- this.setState(s => ((s.siteForm.icon = Some("")), s));
+ this.setState(s => ((s.siteForm.icon = ""), s));
}
handleBannerUpload(url: string) {
- this.setState(s => ((s.siteForm.banner = Some(url)), s));
+ this.setState(s => ((s.siteForm.banner = url), s));
}
handleBannerRemove() {
- this.setState(s => ((s.siteForm.banner = Some("")), s));
+ this.setState(s => ((s.siteForm.banner = ""), s));
}
handleSiteSlurFilterRegex(i: SiteForm, event: any) {
- i.setState(
- s => ((s.siteForm.slur_filter_regex = Some(event.target.value)), s)
- );
+ i.setState(s => ((s.siteForm.slur_filter_regex = event.target.value), s));
}
handleSiteActorNameMaxLength(i: SiteForm, event: any) {
i.setState(
- s => (
- (s.siteForm.actor_name_max_length = Some(Number(event.target.value))), s
- )
+ s => ((s.siteForm.actor_name_max_length = Number(event.target.value)), s)
);
}
handleSiteRateLimitMessage(i: SiteForm, event: any) {
i.setState(
- s => (
- (s.siteForm.rate_limit_message = Some(Number(event.target.value))), s
- )
+ s => ((s.siteForm.rate_limit_message = Number(event.target.value)), s)
);
}
handleSiteRateLimitMessagePerSecond(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.rate_limit_message_per_second = Some(
- Number(event.target.value)
- )),
+ (s.siteForm.rate_limit_message_per_second = Number(event.target.value)),
s
)
);
handleSiteRateLimitPost(i: SiteForm, event: any) {
i.setState(
- s => ((s.siteForm.rate_limit_post = Some(Number(event.target.value))), s)
+ s => ((s.siteForm.rate_limit_post = Number(event.target.value)), s)
);
}
handleSiteRateLimitPostPerSecond(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.rate_limit_post_per_second = Some(
- Number(event.target.value)
- )),
- s
+ (s.siteForm.rate_limit_post_per_second = Number(event.target.value)), s
)
);
}
handleSiteRateLimitImage(i: SiteForm, event: any) {
i.setState(
- s => ((s.siteForm.rate_limit_image = Some(Number(event.target.value))), s)
+ s => ((s.siteForm.rate_limit_image = Number(event.target.value)), s)
);
}
handleSiteRateLimitImagePerSecond(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.rate_limit_image_per_second = Some(
- Number(event.target.value)
- )),
- s
+ (s.siteForm.rate_limit_image_per_second = Number(event.target.value)), s
)
);
}
handleSiteRateLimitComment(i: SiteForm, event: any) {
i.setState(
- s => (
- (s.siteForm.rate_limit_comment = Some(Number(event.target.value))), s
- )
+ s => ((s.siteForm.rate_limit_comment = Number(event.target.value)), s)
);
}
handleSiteRateLimitCommentPerSecond(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.rate_limit_comment_per_second = Some(
- Number(event.target.value)
- )),
+ (s.siteForm.rate_limit_comment_per_second = Number(event.target.value)),
s
)
);
handleSiteRateLimitSearch(i: SiteForm, event: any) {
i.setState(
- s => (
- (s.siteForm.rate_limit_search = Some(Number(event.target.value))), s
- )
+ s => ((s.siteForm.rate_limit_search = Number(event.target.value)), s)
);
}
handleSiteRateLimitSearchPerSecond(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.rate_limit_search_per_second = Some(
- Number(event.target.value)
- )),
+ (s.siteForm.rate_limit_search_per_second = Number(event.target.value)),
s
)
);
handleSiteRateLimitRegister(i: SiteForm, event: any) {
i.setState(
- s => (
- (s.siteForm.rate_limit_register = Some(Number(event.target.value))), s
- )
+ s => ((s.siteForm.rate_limit_register = Number(event.target.value)), s)
);
}
handleSiteRateLimitRegisterPerSecond(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.rate_limit_register_per_second = Some(
- Number(event.target.value)
+ (s.siteForm.rate_limit_register_per_second = Number(
+ event.target.value
)),
s
)
}
handleSiteFederationEnabled(i: SiteForm, event: any) {
- i.state.siteForm.federation_enabled = Some(event.target.checked);
+ i.state.siteForm.federation_enabled = event.target.checked;
i.setState(i.state);
}
handleSiteFederationDebug(i: SiteForm, event: any) {
- i.state.siteForm.federation_debug = Some(event.target.checked);
+ i.state.siteForm.federation_debug = event.target.checked;
i.setState(i.state);
}
handleSiteFederationWorkerCount(i: SiteForm, event: any) {
i.setState(
s => (
- (s.siteForm.federation_worker_count = Some(Number(event.target.value))),
- s
+ (s.siteForm.federation_worker_count = Number(event.target.value)), s
)
);
}
handleSiteCaptchaEnabled(i: SiteForm, event: any) {
- i.state.siteForm.captcha_enabled = Some(event.target.checked);
+ i.state.siteForm.captcha_enabled = event.target.checked;
i.setState(i.state);
}
handleSiteCaptchaDifficulty(i: SiteForm, event: any) {
- i.setState(
- s => ((s.siteForm.captcha_difficulty = Some(event.target.value)), s)
- );
+ i.setState(s => ((s.siteForm.captcha_difficulty = event.target.value), s));
}
handleDiscussionLanguageChange(val: number[]) {
- this.setState(s => ((s.siteForm.discussion_languages = Some(val)), s));
+ this.setState(s => ((s.siteForm.discussion_languages = val), s));
}
handleDefaultPostListingTypeChange(val: ListingType) {
this.setState(
s => (
- (s.siteForm.default_post_listing_type = Some(
- ListingType[ListingType[val]]
- )),
+ (s.siteForm.default_post_listing_type = ListingType[ListingType[val]]),
s
)
);
}
}
-function splitToList(commaList: string): Option<string[]> {
+function splitToList(commaList: string): string[] {
if (commaList !== "") {
let list = commaList.trim().split(",");
- return Some(list);
+ return list;
} else {
- return Some([]);
+ return [];
}
}
-import { None, Option } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
import { PersonViewSafe, Site, SiteAggregates } from "lemmy-js-client";
interface SiteSidebarProps {
site: Site;
showLocal: boolean;
- counts: Option<SiteAggregates>;
- admins: Option<PersonViewSafe[]>;
- online: Option<number>;
+ counts?: SiteAggregates;
+ admins?: PersonViewSafe[];
+ online?: number;
}
interface SiteSidebarState {
}
export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
- private emptyState: SiteSidebarState = {
+ state: SiteSidebarState = {
collapsed: false,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
render() {
<div className="mb-2">{this.siteName()}</div>
{!this.state.collapsed && (
<>
- <BannerIconHeader banner={this.props.site.banner} icon={None} />
+ <BannerIconHeader banner={this.props.site.banner} />
{this.siteInfo()}
</>
)}
let site = this.props.site;
return (
<div>
- {site.description.match({
- some: description => <h6>{description}</h6>,
- none: <></>,
- })}
- {site.sidebar.match({
- some: sidebar => this.siteSidebar(sidebar),
- none: <></>,
- })}
- {this.props.counts.match({
- some: counts => this.badges(counts),
- none: <></>,
- })}
- {this.props.admins.match({
- some: admins => this.admins(admins),
- none: <></>,
- })}
+ {site.description && <h6>{site.description}</h6>}
+ {site.sidebar && this.siteSidebar(site.sidebar)}
+ {this.props.counts && this.badges(this.props.counts)}
+ {this.props.admins && this.admins(this.props.admins)}
</div>
);
}
badges(siteAggregates: SiteAggregates) {
let counts = siteAggregates;
- let online = this.props.online.unwrapOr(1);
+ let online = this.props.online ?? 1;
return (
<ul className="my-2 list-inline">
<li className="list-inline-item badge badge-secondary">
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
import {
ModRemovePostView,
ModTransferCommunityView,
PersonSafe,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
import {
amAdmin,
amMod,
- auth,
choicesConfig,
debounce,
fetchLimit,
fetchUsers,
isBrowser,
+ myAuth,
setIsoData,
toast,
wsClient,
type ModlogType = {
id: number;
type_: ModlogActionType;
- moderator: Option<PersonSafe>;
+ moderator?: PersonSafe;
view:
| ModRemovePostView
| ModLockPostView
}
interface ModlogState {
- res: Option<GetModlogResponse>;
- communityId: Option<number>;
- communityMods: Option<CommunityModeratorView[]>;
- communityName: Option<string>;
+ res?: GetModlogResponse;
+ communityId?: number;
+ communityMods?: CommunityModeratorView[];
+ communityName?: string;
page: number;
siteRes: GetSiteResponse;
loading: boolean;
filter_action: ModlogActionType;
- filter_user: Option<number>;
- filter_mod: Option<number>;
+ filter_user?: number;
+ filter_mod?: number;
}
export class Modlog extends Component<any, ModlogState> {
- private isoData = setIsoData(
- this.context,
- GetModlogResponse,
- GetCommunityResponse
- );
- private subscription: Subscription;
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
private userChoices: any;
private modChoices: any;
- private emptyState: ModlogState = {
- res: None,
- communityId: None,
- communityMods: None,
- communityName: None,
+ state: ModlogState = {
page: 1,
loading: true,
siteRes: this.isoData.site_res,
filter_action: ModlogActionType.All,
- filter_user: None,
- filter_mod: None,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePageChange = this.handlePageChange.bind(this);
this.parseMessage = this.parseMessage.bind(this);
this.state = {
...this.state,
communityId: this.props.match.params.community_id
- ? Some(Number(this.props.match.params.community_id))
- : None,
+ ? Number(this.props.match.params.community_id)
+ : undefined,
};
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- res: Some(this.isoData.routeData[0] as GetModlogResponse),
+ res: this.isoData.routeData[0] as GetModlogResponse,
};
- if (this.isoData.routeData[1]) {
- // Getting the moderators
- let communityRes = Some(
- this.isoData.routeData[1] as GetCommunityResponse
- );
- this.state = {
- ...this.state,
- communityMods: communityRes.map(c => c.moderators),
- };
- }
+ let communityRes: GetCommunityResponse | undefined =
+ this.isoData.routeData[1];
+
+ // Getting the moderators
+ this.state = {
+ ...this.state,
+ communityMods: communityRes?.moderators,
+ };
this.state = { ...this.state, loading: false };
} else {
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
switch (i.type_) {
case ModlogActionType.ModRemovePost: {
let mrpv = i.view as ModRemovePostView;
+ let reason = mrpv.mod_remove_post.reason;
return (
<>
<span>
- {mrpv.mod_remove_post.removed.unwrapOr(false)
- ? "Removed "
- : "Restored "}
+ {mrpv.mod_remove_post.removed ? "Removed " : "Restored "}
</span>
<span>
Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
</span>
- <span>
- {mrpv.mod_remove_post.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
</>
);
}
let mlpv = i.view as ModLockPostView;
return (
<>
- <span>
- {mlpv.mod_lock_post.locked.unwrapOr(false)
- ? "Locked "
- : "Unlocked "}
- </span>
+ <span>{mlpv.mod_lock_post.locked ? "Locked " : "Unlocked "}</span>
<span>
Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
</span>
}
case ModlogActionType.ModRemoveComment: {
let mrc = i.view as ModRemoveCommentView;
+ let reason = mrc.mod_remove_comment.reason;
return (
<>
<span>
- {mrc.mod_remove_comment.removed.unwrapOr(false)
- ? "Removed "
- : "Restored "}
+ {mrc.mod_remove_comment.removed ? "Removed " : "Restored "}
</span>
<span>
Comment{" "}
{" "}
by <PersonListing person={mrc.commenter} />
</span>
- <span>
- {mrc.mod_remove_comment.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
</>
);
}
case ModlogActionType.ModRemoveCommunity: {
let mrco = i.view as ModRemoveCommunityView;
+ let reason = mrco.mod_remove_community.reason;
+ let expires = mrco.mod_remove_community.expires;
return (
<>
<span>
- {mrco.mod_remove_community.removed.unwrapOr(false)
- ? "Removed "
- : "Restored "}
+ {mrco.mod_remove_community.removed ? "Removed " : "Restored "}
</span>
<span>
Community <CommunityLink community={mrco.community} />
</span>
- <span>
- {mrco.mod_remove_community.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
- <span>
- {mrco.mod_remove_community.expires.match({
- some: expires => (
- <div>expires: {moment.utc(expires).fromNow()}</div>
- ),
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
+ {expires && (
+ <span>
+ <div>expires: {moment.utc(expires).fromNow()}</div>
+ </span>
+ )}
</>
);
}
case ModlogActionType.ModBanFromCommunity: {
let mbfc = i.view as ModBanFromCommunityView;
+ let reason = mbfc.mod_ban_from_community.reason;
+ let expires = mbfc.mod_ban_from_community.expires;
return (
<>
<span>
- {mbfc.mod_ban_from_community.banned.unwrapOr(false)
- ? "Banned "
- : "Unbanned "}{" "}
+ {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
</span>
<span>
<PersonListing person={mbfc.banned_person} />
<span>
<CommunityLink community={mbfc.community} />
</span>
- <span>
- {mbfc.mod_ban_from_community.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
- <span>
- {mbfc.mod_ban_from_community.expires.match({
- some: expires => (
- <div>expires: {moment.utc(expires).fromNow()}</div>
- ),
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
+ {expires && (
+ <span>
+ <div>expires: {moment.utc(expires).fromNow()}</div>
+ </span>
+ )}
</>
);
}
return (
<>
<span>
- {mac.mod_add_community.removed.unwrapOr(false)
- ? "Removed "
- : "Appointed "}{" "}
+ {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
</span>
<span>
<PersonListing person={mac.modded_person} />
return (
<>
<span>
- {mtc.mod_transfer_community.removed.unwrapOr(false)
- ? "Removed "
- : "Transferred "}{" "}
+ {mtc.mod_transfer_community.removed ? "Removed " : "Transferred "}{" "}
</span>
<span>
<CommunityLink community={mtc.community} />
}
case ModlogActionType.ModBan: {
let mb = i.view as ModBanView;
+ let reason = mb.mod_ban.reason;
+ let expires = mb.mod_ban.expires;
return (
<>
- <span>
- {mb.mod_ban.banned.unwrapOr(false) ? "Banned " : "Unbanned "}{" "}
- </span>
+ <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>
<span>
<PersonListing person={mb.banned_person} />
</span>
- <span>
- {mb.mod_ban.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
- <span>
- {mb.mod_ban.expires.match({
- some: expires => (
- <div>expires: {moment.utc(expires).fromNow()}</div>
- ),
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
+ {expires && (
+ <span>
+ <div>expires: {moment.utc(expires).fromNow()}</div>
+ </span>
+ )}
</>
);
}
let ma = i.view as ModAddView;
return (
<>
- <span>
- {ma.mod_add.removed.unwrapOr(false) ? "Removed " : "Appointed "}{" "}
- </span>
+ <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>
<span>
<PersonListing person={ma.modded_person} />
</span>
}
case ModlogActionType.AdminPurgePerson: {
let ap = i.view as AdminPurgePersonView;
+ let reason = ap.admin_purge_person.reason;
return (
<>
<span>Purged a Person</span>
- <span>
- {ap.admin_purge_person.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
</>
);
}
case ModlogActionType.AdminPurgeCommunity: {
let ap = i.view as AdminPurgeCommunityView;
+ let reason = ap.admin_purge_community.reason;
return (
<>
<span>Purged a Community</span>
- <span>
- {ap.admin_purge_community.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
</>
);
}
case ModlogActionType.AdminPurgePost: {
let ap = i.view as AdminPurgePostView;
+ let reason = ap.admin_purge_post.reason;
return (
<>
<span>Purged a Post from from </span>
<CommunityLink community={ap.community} />
- <span>
- {ap.admin_purge_post.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
</>
);
}
case ModlogActionType.AdminPurgeComment: {
let ap = i.view as AdminPurgeCommentView;
+ let reason = ap.admin_purge_comment.reason;
return (
<>
<span>
Purged a Comment from{" "}
<Link to={`/post/${ap.post.id}`}>{ap.post.name}</Link>
</span>
- <span>
- {ap.admin_purge_comment.reason.match({
- some: reason => <div>reason: {reason}</div>,
- none: <></>,
- })}
- </span>
+ {reason && (
+ <span>
+ <div>reason: {reason}</div>
+ </span>
+ )}
</>
);
}
}
combined() {
- let combined = this.state.res.map(this.buildCombined).unwrapOr([]);
+ let res = this.state.res;
+ let combined = res ? this.buildCombined(res) : [];
return (
<tbody>
{combined.map(i => (
<tr key={i.id}>
<td>
- <MomentTime published={i.when_} updated={None} />
+ <MomentTime published={i.when_} />
</td>
<td>
- {this.amAdminOrMod ? (
- <PersonListing person={i.moderator.unwrap()} />
+ {this.amAdminOrMod && i.moderator ? (
+ <PersonListing person={i.moderator} />
) : (
<div>{this.modOrAdminText(i.moderator)}</div>
)}
return amAdmin() || amMod(this.state.communityMods);
}
- modOrAdminText(person: Option<PersonSafe>): string {
- return person.match({
- some: res =>
- this.isoData.site_res.admins.map(a => a.person.id).includes(res.id)
- ? i18n.t("admin")
- : i18n.t("mod"),
- none: i18n.t("mod"),
- });
+ modOrAdminText(person?: PersonSafe): string {
+ return person
+ ? this.isoData.site_res.admins.map(a => a.person.id).includes(person.id)
+ ? i18n.t("admin")
+ : i18n.t("mod")
+ : i18n.t("mod");
}
get documentTitle(): string {
}
render() {
+ let communityName = this.state.communityName;
return (
<div className="container-lg">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
{this.state.loading ? (
<h5>
) : (
<div>
<h5>
- {this.state.communityName.match({
- some: name => (
- <Link className="text-body" to={`/c/${name}`}>
- /c/{name}{" "}
- </Link>
- ),
- none: <></>,
- })}
+ {communityName && (
+ <Link className="text-body" to={`/c/${communityName}`}>
+ /c/{communityName}{" "}
+ </Link>
+ )}
<span>{i18n.t("modlog")}</span>
</h5>
<div className="form-row">
<select
id="filter-mod"
className="form-control"
- value={toUndefined(this.state.filter_mod)}
+ value={this.state.filter_mod}
>
<option>{i18n.t("filter_by_mod")}</option>
</select>
<select
id="filter-user"
className="form-control"
- value={toUndefined(this.state.filter_user)}
+ value={this.state.filter_user}
>
<option>{i18n.t("filter_by_user")}</option>
</select>
}
refetch() {
- let modlogForm = new GetModlog({
+ let auth = myAuth(false);
+ let modlogForm: GetModlog = {
community_id: this.state.communityId,
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- auth: auth(false).ok(),
+ page: this.state.page,
+ limit: fetchLimit,
type_: this.state.filter_action,
other_person_id: this.state.filter_user,
mod_person_id: this.state.filter_mod,
- });
+ auth,
+ };
WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
- this.state.communityId.match({
- some: id => {
- let communityForm = new GetCommunity({
- id: Some(id),
- name: None,
- auth: auth(false).ok(),
- });
- WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
- },
- none: void 0,
- });
+ let communityId = this.state.communityId;
+ if (communityId) {
+ let communityForm: GetCommunity = {
+ id: communityId,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
+ }
}
setupUserFilter() {
this.userChoices.passedElement.element.addEventListener(
"choice",
(e: any) => {
- this.setState({ filter_user: Some(Number(e.detail.choice.value)) });
+ this.setState({ filter_user: Number(e.detail.choice.value) });
this.refetch();
},
false
this.modChoices.passedElement.element.addEventListener(
"choice",
(e: any) => {
- this.setState({ filter_mod: Some(Number(e.detail.choice.value)) });
+ this.setState({ filter_mod: Number(e.detail.choice.value) });
this.refetch();
},
false
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split("/");
- let communityId = Some(pathSplit[3]).map(Number);
+ let communityId = pathSplit[3] ? Number(pathSplit[3]) : undefined;
+ let auth = req.auth;
let promises: Promise<any>[] = [];
- let modlogForm = new GetModlog({
- page: Some(1),
- limit: Some(fetchLimit),
+ let modlogForm: GetModlog = {
+ page: 1,
+ limit: fetchLimit,
community_id: communityId,
- mod_person_id: None,
- auth: req.auth,
type_: ModlogActionType.All,
- other_person_id: None,
- });
+ auth,
+ };
promises.push(req.client.getModlog(modlogForm));
- if (communityId.isSome()) {
- let communityForm = new GetCommunity({
+ if (communityId) {
+ let communityForm: GetCommunity = {
id: communityId,
- name: None,
auth: req.auth,
- });
+ };
promises.push(req.client.getCommunity(communityForm));
} else {
promises.push(Promise.resolve());
toast(i18n.t(msg.error), "danger");
return;
} else if (op == UserOperation.GetModlog) {
- let data = wsJsonToRes<GetModlogResponse>(msg, GetModlogResponse);
+ let data = wsJsonToRes<GetModlogResponse>(msg);
window.scrollTo(0, 0);
- this.setState({ res: Some(data), loading: false });
+ this.setState({ res: data, loading: false });
this.setupUserFilter();
this.setupModFilter();
} else if (op == UserOperation.GetCommunity) {
- let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
+ let data = wsJsonToRes<GetCommunityResponse>(msg);
this.setState({
- communityMods: Some(data.moderators),
- communityName: Some(data.community_view.community.name),
+ communityMods: data.moderators,
+ communityName: data.community_view.community.name,
});
}
}
-import { None, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
BlockPersonResponse,
import { CommentViewType, InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
commentsToFlatNodes,
createCommentLikeRes,
editCommentRes,
enableDownvotes,
fetchLimit,
isBrowser,
+ myAuth,
relTags,
saveCommentRes,
setIsoData,
}
export class Inbox extends Component<any, InboxState> {
- private isoData = setIsoData(
- this.context,
- GetRepliesResponse,
- GetPersonMentionsResponse,
- PrivateMessagesResponse
- );
- private subscription: Subscription;
- private emptyState: InboxState = {
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: InboxState = {
unreadOrAll: UnreadOrAll.Unread,
messageType: MessageType.All,
replies: [],
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
this.handlePageChange = this.handlePageChange.bind(this);
- if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+ if (!UserService.Instance.myUserInfo && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`);
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
get documentTitle(): string {
- return UserService.Instance.myUserInfo.match({
- some: mui =>
- `@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
+ let mui = UserService.Instance.myUserInfo;
+ return mui
+ ? `@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
this.state.siteRes.site_view.site.name
- }`,
- none: "",
- });
+ }`
+ : "";
}
render() {
- let inboxRss = auth()
- .ok()
- .map(a => `/feeds/inbox/${a}.xml`);
+ let auth = myAuth();
+ let inboxRss = auth ? `/feeds/inbox/${auth}.xml` : undefined;
return (
<div className="container-lg">
{this.state.loading ? (
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<h5 className="mb-2">
{i18n.t("inbox")}
- {inboxRss.match({
- some: rss => (
- <small>
- <a href={rss} title="RSS" rel={relTags}>
- <Icon icon="rss" classes="ml-2 text-muted small" />
- </a>
- <link
- rel="alternate"
- type="application/atom+xml"
- href={rss}
- />
- </small>
- ),
- none: <></>,
- })}
+ {inboxRss && (
+ <small>
+ <a href={inboxRss} title="RSS" rel={relTags}>
+ <Icon icon="rss" classes="ml-2 text-muted small" />
+ </a>
+ <link
+ rel="alternate"
+ type="application/atom+xml"
+ href={inboxRss}
+ />
+ </small>
+ )}
</h5>
{this.state.replies.length +
this.state.mentions.length +
{ comment_view: i.view as CommentView, children: [], depth: 0 },
]}
viewType={CommentViewType.Flat}
- moderators={None}
- admins={None}
- maxCommentsShown={None}
noIndent
markable
showCommunity
},
]}
viewType={CommentViewType.Flat}
- moderators={None}
- admins={None}
- maxCommentsShown={None}
noIndent
markable
showCommunity
<CommentNodes
nodes={commentsToFlatNodes(this.state.replies)}
viewType={CommentViewType.Flat}
- moderators={None}
- admins={None}
- maxCommentsShown={None}
noIndent
markable
showCommunity
key={umv.person_mention.id}
nodes={[{ comment_view: umv, children: [], depth: 0 }]}
viewType={CommentViewType.Flat}
- moderators={None}
- admins={None}
- maxCommentsShown={None}
noIndent
markable
showCommunity
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let promises: Promise<any>[] = [];
- let sort = Some(CommentSortType.New);
-
- // It can be /u/me, or /username/1
- let repliesForm = new GetReplies({
- sort,
- unread_only: Some(true),
- page: Some(1),
- limit: Some(fetchLimit),
- auth: req.auth.unwrap(),
- });
- promises.push(req.client.getReplies(repliesForm));
-
- let personMentionsForm = new GetPersonMentions({
- sort,
- unread_only: Some(true),
- page: Some(1),
- limit: Some(fetchLimit),
- auth: req.auth.unwrap(),
- });
- promises.push(req.client.getPersonMentions(personMentionsForm));
-
- let privateMessagesForm = new GetPrivateMessages({
- unread_only: Some(true),
- page: Some(1),
- limit: Some(fetchLimit),
- auth: req.auth.unwrap(),
- });
- promises.push(req.client.getPrivateMessages(privateMessagesForm));
+ let sort = CommentSortType.New;
+ let auth = req.auth;
+
+ if (auth) {
+ // It can be /u/me, or /username/1
+ let repliesForm: GetReplies = {
+ sort,
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ auth,
+ };
+ promises.push(req.client.getReplies(repliesForm));
+
+ let personMentionsForm: GetPersonMentions = {
+ sort,
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ auth,
+ };
+ promises.push(req.client.getPersonMentions(personMentionsForm));
+
+ let privateMessagesForm: GetPrivateMessages = {
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ auth,
+ };
+ promises.push(req.client.getPrivateMessages(privateMessagesForm));
+ }
return promises;
}
refetch() {
- let sort = Some(this.state.sort);
- let unread_only = Some(this.state.unreadOrAll == UnreadOrAll.Unread);
- let page = Some(this.state.page);
- let limit = Some(fetchLimit);
-
- let repliesForm = new GetReplies({
- sort,
- unread_only,
- page,
- limit,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
-
- let personMentionsForm = new GetPersonMentions({
- sort,
- unread_only,
- page,
- limit,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(
- wsClient.getPersonMentions(personMentionsForm)
- );
+ let sort = this.state.sort;
+ let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread;
+ let page = this.state.page;
+ let limit = fetchLimit;
+ let auth = myAuth();
+
+ if (auth) {
+ let repliesForm: GetReplies = {
+ sort,
+ unread_only,
+ page,
+ limit,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
+
+ let personMentionsForm: GetPersonMentions = {
+ sort,
+ unread_only,
+ page,
+ limit,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.getPersonMentions(personMentionsForm)
+ );
- let privateMessagesForm = new GetPrivateMessages({
- unread_only,
- page,
- limit,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(
- wsClient.getPrivateMessages(privateMessagesForm)
- );
+ let privateMessagesForm: GetPrivateMessages = {
+ unread_only,
+ page,
+ limit,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.getPrivateMessages(privateMessagesForm)
+ );
+ }
}
handleSortChange(val: CommentSortType) {
}
markAllAsRead(i: Inbox) {
- WebSocketService.Instance.send(
- wsClient.markAllAsRead({
- auth: auth().unwrap(),
- })
- );
- i.setState({ replies: [], mentions: [], messages: [] });
- i.setState({ combined: i.buildCombined() });
- UserService.Instance.unreadInboxCountSub.next(0);
- window.scrollTo(0, 0);
- i.setState(i.state);
+ let auth = myAuth();
+ if (auth) {
+ WebSocketService.Instance.send(
+ wsClient.markAllAsRead({
+ auth,
+ })
+ );
+ i.setState({ replies: [], mentions: [], messages: [] });
+ i.setState({ combined: i.buildCombined() });
+ UserService.Instance.unreadInboxCountSub.next(0);
+ window.scrollTo(0, 0);
+ i.setState(i.state);
+ }
}
sendUnreadCount(read: boolean) {
} else if (msg.reconnect) {
this.refetch();
} else if (op == UserOperation.GetReplies) {
- let data = wsJsonToRes<GetRepliesResponse>(msg, GetRepliesResponse);
+ let data = wsJsonToRes<GetRepliesResponse>(msg);
this.setState({ replies: data.replies });
this.setState({ combined: this.buildCombined(), loading: false });
window.scrollTo(0, 0);
setupTippy();
} else if (op == UserOperation.GetPersonMentions) {
- let data = wsJsonToRes<GetPersonMentionsResponse>(
- msg,
- GetPersonMentionsResponse
- );
+ let data = wsJsonToRes<GetPersonMentionsResponse>(msg);
this.setState({ mentions: data.mentions });
this.setState({ combined: this.buildCombined() });
window.scrollTo(0, 0);
setupTippy();
} else if (op == UserOperation.GetPrivateMessages) {
- let data = wsJsonToRes<PrivateMessagesResponse>(
- msg,
- PrivateMessagesResponse
- );
+ let data = wsJsonToRes<PrivateMessagesResponse>(msg);
this.setState({ messages: data.private_messages });
this.setState({ combined: this.buildCombined() });
window.scrollTo(0, 0);
setupTippy();
} else if (op == UserOperation.EditPrivateMessage) {
- let data = wsJsonToRes<PrivateMessageResponse>(
- msg,
- PrivateMessageResponse
- );
- let found: PrivateMessageView = this.state.messages.find(
+ let data = wsJsonToRes<PrivateMessageResponse>(msg);
+ let found = this.state.messages.find(
m =>
m.private_message.id === data.private_message_view.private_message.id
);
if (found) {
let combinedView = this.state.combined.find(
i => i.id == data.private_message_view.private_message.id
- ).view as PrivateMessageView;
- found.private_message.content = combinedView.private_message.content =
- data.private_message_view.private_message.content;
- found.private_message.updated = combinedView.private_message.updated =
- data.private_message_view.private_message.updated;
+ )?.view as PrivateMessageView | undefined;
+ if (combinedView) {
+ found.private_message.content = combinedView.private_message.content =
+ data.private_message_view.private_message.content;
+ found.private_message.updated = combinedView.private_message.updated =
+ data.private_message_view.private_message.updated;
+ }
}
this.setState(this.state);
} else if (op == UserOperation.DeletePrivateMessage) {
- let data = wsJsonToRes<PrivateMessageResponse>(
- msg,
- PrivateMessageResponse
- );
- let found: PrivateMessageView = this.state.messages.find(
+ let data = wsJsonToRes<PrivateMessageResponse>(msg);
+ let found = this.state.messages.find(
m =>
m.private_message.id === data.private_message_view.private_message.id
);
if (found) {
let combinedView = this.state.combined.find(
i => i.id == data.private_message_view.private_message.id
- ).view as PrivateMessageView;
- found.private_message.deleted = combinedView.private_message.deleted =
- data.private_message_view.private_message.deleted;
- found.private_message.updated = combinedView.private_message.updated =
- data.private_message_view.private_message.updated;
+ )?.view as PrivateMessageView | undefined;
+ if (combinedView) {
+ found.private_message.deleted = combinedView.private_message.deleted =
+ data.private_message_view.private_message.deleted;
+ found.private_message.updated = combinedView.private_message.updated =
+ data.private_message_view.private_message.updated;
+ }
}
this.setState(this.state);
} else if (op == UserOperation.MarkPrivateMessageAsRead) {
- let data = wsJsonToRes<PrivateMessageResponse>(
- msg,
- PrivateMessageResponse
- );
- let found: PrivateMessageView = this.state.messages.find(
+ let data = wsJsonToRes<PrivateMessageResponse>(msg);
+ let found = this.state.messages.find(
m =>
m.private_message.id === data.private_message_view.private_message.id
);
i =>
i.id == data.private_message_view.private_message.id &&
i.type_ == ReplyEnum.Message
- ).view as PrivateMessageView;
- found.private_message.updated = combinedView.private_message.updated =
- data.private_message_view.private_message.updated;
-
- // If youre in the unread view, just remove it from the list
- if (
- this.state.unreadOrAll == UnreadOrAll.Unread &&
- data.private_message_view.private_message.read
- ) {
- this.setState({
- messages: this.state.messages.filter(
- r =>
- r.private_message.id !==
- data.private_message_view.private_message.id
- ),
- });
- this.setState({
- combined: this.state.combined.filter(
- r => r.id !== data.private_message_view.private_message.id
- ),
- });
- } else {
- found.private_message.read = combinedView.private_message.read =
- data.private_message_view.private_message.read;
+ )?.view as PrivateMessageView | undefined;
+ if (combinedView) {
+ found.private_message.updated = combinedView.private_message.updated =
+ data.private_message_view.private_message.updated;
+
+ // If youre in the unread view, just remove it from the list
+ if (
+ this.state.unreadOrAll == UnreadOrAll.Unread &&
+ data.private_message_view.private_message.read
+ ) {
+ this.setState({
+ messages: this.state.messages.filter(
+ r =>
+ r.private_message.id !==
+ data.private_message_view.private_message.id
+ ),
+ });
+ this.setState({
+ combined: this.state.combined.filter(
+ r => r.id !== data.private_message_view.private_message.id
+ ),
+ });
+ } else {
+ found.private_message.read = combinedView.private_message.read =
+ data.private_message_view.private_message.read;
+ }
}
}
this.sendUnreadCount(data.private_message_view.private_message.read);
op == UserOperation.DeleteComment ||
op == UserOperation.RemoveComment
) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
editCommentRes(data.comment_view, this.state.replies);
this.setState(this.state);
} else if (op == UserOperation.MarkCommentReplyAsRead) {
- let data = wsJsonToRes<CommentReplyResponse>(msg, CommentReplyResponse);
+ let data = wsJsonToRes<CommentReplyResponse>(msg);
let found = this.state.replies.find(
c => c.comment_reply.id == data.comment_reply_view.comment_reply.id
i =>
i.id == data.comment_reply_view.comment_reply.id &&
i.type_ == ReplyEnum.Reply
- ).view as CommentReplyView;
- found.comment.content = combinedView.comment.content =
- data.comment_reply_view.comment.content;
- found.comment.updated = combinedView.comment.updated =
- data.comment_reply_view.comment.updated;
- found.comment.removed = combinedView.comment.removed =
- data.comment_reply_view.comment.removed;
- found.comment.deleted = combinedView.comment.deleted =
- data.comment_reply_view.comment.deleted;
- found.counts.upvotes = combinedView.counts.upvotes =
- data.comment_reply_view.counts.upvotes;
- found.counts.downvotes = combinedView.counts.downvotes =
- data.comment_reply_view.counts.downvotes;
- found.counts.score = combinedView.counts.score =
- data.comment_reply_view.counts.score;
-
- // If youre in the unread view, just remove it from the list
- if (
- this.state.unreadOrAll == UnreadOrAll.Unread &&
- data.comment_reply_view.comment_reply.read
- ) {
- this.setState({
- replies: this.state.replies.filter(
- r =>
- r.comment_reply.id !== data.comment_reply_view.comment_reply.id
- ),
- });
- this.setState({
- combined: this.state.combined.filter(
- r => r.id !== data.comment_reply_view.comment_reply.id
- ),
- });
- } else {
- found.comment_reply.read = combinedView.comment_reply.read =
- data.comment_reply_view.comment_reply.read;
+ )?.view as CommentReplyView | undefined;
+ if (combinedView) {
+ found.comment.content = combinedView.comment.content =
+ data.comment_reply_view.comment.content;
+ found.comment.updated = combinedView.comment.updated =
+ data.comment_reply_view.comment.updated;
+ found.comment.removed = combinedView.comment.removed =
+ data.comment_reply_view.comment.removed;
+ found.comment.deleted = combinedView.comment.deleted =
+ data.comment_reply_view.comment.deleted;
+ found.counts.upvotes = combinedView.counts.upvotes =
+ data.comment_reply_view.counts.upvotes;
+ found.counts.downvotes = combinedView.counts.downvotes =
+ data.comment_reply_view.counts.downvotes;
+ found.counts.score = combinedView.counts.score =
+ data.comment_reply_view.counts.score;
+
+ // If youre in the unread view, just remove it from the list
+ if (
+ this.state.unreadOrAll == UnreadOrAll.Unread &&
+ data.comment_reply_view.comment_reply.read
+ ) {
+ this.setState({
+ replies: this.state.replies.filter(
+ r =>
+ r.comment_reply.id !==
+ data.comment_reply_view.comment_reply.id
+ ),
+ });
+ this.setState({
+ combined: this.state.combined.filter(
+ r => r.id !== data.comment_reply_view.comment_reply.id
+ ),
+ });
+ } else {
+ found.comment_reply.read = combinedView.comment_reply.read =
+ data.comment_reply_view.comment_reply.read;
+ }
}
}
this.sendUnreadCount(data.comment_reply_view.comment_reply.read);
this.setState(this.state);
} else if (op == UserOperation.MarkPersonMentionAsRead) {
- let data = wsJsonToRes<PersonMentionResponse>(msg, PersonMentionResponse);
+ let data = wsJsonToRes<PersonMentionResponse>(msg);
// TODO this might not be correct, it might need to use the comment id
let found = this.state.mentions.find(
i =>
i.id == data.person_mention_view.person_mention.id &&
i.type_ == ReplyEnum.Mention
- ).view as PersonMentionView;
- found.comment.content = combinedView.comment.content =
- data.person_mention_view.comment.content;
- found.comment.updated = combinedView.comment.updated =
- data.person_mention_view.comment.updated;
- found.comment.removed = combinedView.comment.removed =
- data.person_mention_view.comment.removed;
- found.comment.deleted = combinedView.comment.deleted =
- data.person_mention_view.comment.deleted;
- found.counts.upvotes = combinedView.counts.upvotes =
- data.person_mention_view.counts.upvotes;
- found.counts.downvotes = combinedView.counts.downvotes =
- data.person_mention_view.counts.downvotes;
- found.counts.score = combinedView.counts.score =
- data.person_mention_view.counts.score;
-
- // If youre in the unread view, just remove it from the list
- if (
- this.state.unreadOrAll == UnreadOrAll.Unread &&
- data.person_mention_view.person_mention.read
- ) {
- this.setState({
- mentions: this.state.mentions.filter(
- r =>
- r.person_mention.id !==
- data.person_mention_view.person_mention.id
- ),
- });
- this.setState({
- combined: this.state.combined.filter(
- r => r.id !== data.person_mention_view.person_mention.id
- ),
- });
- } else {
- // TODO test to make sure these mentions are getting marked as read
- found.person_mention.read = combinedView.person_mention.read =
- data.person_mention_view.person_mention.read;
+ )?.view as PersonMentionView | undefined;
+ if (combinedView) {
+ found.comment.content = combinedView.comment.content =
+ data.person_mention_view.comment.content;
+ found.comment.updated = combinedView.comment.updated =
+ data.person_mention_view.comment.updated;
+ found.comment.removed = combinedView.comment.removed =
+ data.person_mention_view.comment.removed;
+ found.comment.deleted = combinedView.comment.deleted =
+ data.person_mention_view.comment.deleted;
+ found.counts.upvotes = combinedView.counts.upvotes =
+ data.person_mention_view.counts.upvotes;
+ found.counts.downvotes = combinedView.counts.downvotes =
+ data.person_mention_view.counts.downvotes;
+ found.counts.score = combinedView.counts.score =
+ data.person_mention_view.counts.score;
+
+ // If youre in the unread view, just remove it from the list
+ if (
+ this.state.unreadOrAll == UnreadOrAll.Unread &&
+ data.person_mention_view.person_mention.read
+ ) {
+ this.setState({
+ mentions: this.state.mentions.filter(
+ r =>
+ r.person_mention.id !==
+ data.person_mention_view.person_mention.id
+ ),
+ });
+ this.setState({
+ combined: this.state.combined.filter(
+ r => r.id !== data.person_mention_view.person_mention.id
+ ),
+ });
+ } else {
+ // TODO test to make sure these mentions are getting marked as read
+ found.person_mention.read = combinedView.person_mention.read =
+ data.person_mention_view.person_mention.read;
+ }
}
}
this.sendUnreadCount(data.person_mention_view.person_mention.read);
this.setState(this.state);
} else if (op == UserOperation.CreatePrivateMessage) {
- let data = wsJsonToRes<PrivateMessageResponse>(
- msg,
- PrivateMessageResponse
- );
- UserService.Instance.myUserInfo.match({
- some: mui => {
- if (
- data.private_message_view.recipient.id ==
- mui.local_user_view.person.id
- ) {
- this.state.messages.unshift(data.private_message_view);
- this.state.combined.unshift(
- this.messageToReplyType(data.private_message_view)
- );
- this.setState(this.state);
- }
- },
- none: void 0,
- });
+ let data = wsJsonToRes<PrivateMessageResponse>(msg);
+ let mui = UserService.Instance.myUserInfo;
+ if (
+ data.private_message_view.recipient.id == mui?.local_user_view.person.id
+ ) {
+ this.state.messages.unshift(data.private_message_view);
+ this.state.combined.unshift(
+ this.messageToReplyType(data.private_message_view)
+ );
+ this.setState(this.state);
+ }
} else if (op == UserOperation.SaveComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
saveCommentRes(data.comment_view, this.state.replies);
this.setState(this.state);
setupTippy();
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
createCommentLikeRes(data.comment_view, this.state.replies);
this.setState(this.state);
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
+ let data = wsJsonToRes<BlockPersonResponse>(msg);
updatePersonBlock(data);
} else if (op == UserOperation.CreatePostReport) {
- let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+ let data = wsJsonToRes<PostReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
} else if (op == UserOperation.CreateCommentReport) {
- let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+ let data = wsJsonToRes<CommentReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
} else if (op == UserOperation.CreatePrivateMessageReport) {
- let data = wsJsonToRes<PrivateMessageReportResponse>(
- msg,
- PrivateMessageReportResponse
- );
+ let data = wsJsonToRes<PrivateMessageReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
-import { None } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
GetSiteResponse,
LoginResponse,
- PasswordChange as PasswordChangeForm,
+ PasswordChange as PWordChange,
UserOperation,
wsJsonToRes,
wsUserOp,
import { Spinner } from "../common/icon";
interface State {
- passwordChangeForm: PasswordChangeForm;
+ form: {
+ token: string;
+ password?: string;
+ password_verify?: string;
+ };
loading: boolean;
siteRes: GetSiteResponse;
}
export class PasswordChange extends Component<any, State> {
private isoData = setIsoData(this.context);
- private subscription: Subscription;
+ private subscription?: Subscription;
- emptyState: State = {
- passwordChangeForm: new PasswordChangeForm({
+ state: State = {
+ form: {
token: this.props.match.params.token,
- password: undefined,
- password_verify: undefined,
- }),
+ },
loading: false,
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
<input
id="new-password"
type="password"
- value={this.state.passwordChangeForm.password}
+ value={this.state.form.password}
onInput={linkEvent(this, this.handlePasswordChange)}
className="form-control"
required
<input
id="verify-password"
type="password"
- value={this.state.passwordChangeForm.password_verify}
+ value={this.state.form.password_verify}
onInput={linkEvent(this, this.handleVerifyPasswordChange)}
className="form-control"
required
}
handlePasswordChange(i: PasswordChange, event: any) {
- i.state.passwordChangeForm.password = event.target.value;
+ i.state.form.password = event.target.value;
i.setState(i.state);
}
handleVerifyPasswordChange(i: PasswordChange, event: any) {
- i.state.passwordChangeForm.password_verify = event.target.value;
+ i.state.form.password_verify = event.target.value;
i.setState(i.state);
}
event.preventDefault();
i.setState({ loading: true });
- WebSocketService.Instance.send(
- wsClient.passwordChange(i.state.passwordChangeForm)
- );
+ let password = i.state.form.password;
+ let password_verify = i.state.form.password_verify;
+
+ if (password && password_verify) {
+ let form: PWordChange = {
+ token: i.state.form.token,
+ password,
+ password_verify,
+ };
+
+ WebSocketService.Instance.send(wsClient.passwordChange(form));
+ }
}
parseMessage(msg: any) {
this.setState({ loading: false });
return;
} else if (op == UserOperation.PasswordChange) {
- let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
- this.setState(this.emptyState);
+ let data = wsJsonToRes<LoginResponse>(msg);
UserService.Instance.login(data);
this.props.history.push("/");
location.reload();
-import { None, Some } from "@sniptt/monads/build";
import { Component } from "inferno";
import {
CommentView,
key={i.id}
nodes={[{ comment_view: c, children: [], depth: 0 }]}
viewType={CommentViewType.Flat}
- admins={Some(this.props.admins)}
- moderators={None}
- maxCommentsShown={None}
+ admins={this.props.admins}
noBorder
noIndent
showCommunity
<PostListing
key={i.id}
post_view={p}
- admins={Some(this.props.admins)}
- duplicates={None}
- moderators={None}
+ admins={this.props.admins}
showCommunity
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
<CommentNodes
nodes={commentsToFlatNodes(this.props.personRes.comments)}
viewType={CommentViewType.Flat}
- admins={Some(this.props.admins)}
- moderators={None}
- maxCommentsShown={None}
+ admins={this.props.admins}
noIndent
showCommunity
showContext
<>
<PostListing
post_view={post}
- admins={Some(this.props.admins)}
+ admins={this.props.admins}
showCommunity
- duplicates={None}
- moderators={None}
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
allLanguages={this.props.allLanguages}
let displayName = this.props.useApubName
? apubName
- : person.display_name.unwrapOr(apubName);
+ : person.display_name ?? apubName;
- if (this.props.showApubName && !local && person.display_name.isSome()) {
+ if (this.props.showApubName && !local && person.display_name) {
displayName = `${displayName} (${apubName})`;
}
}
avatarAndName(displayName: string) {
+ let avatar = this.props.person.avatar;
return (
<>
- {this.props.person.avatar.match({
- some: avatar =>
- !this.props.hideAvatar &&
- showAvatars() && <PictrsImage src={avatar} icon />,
- none: <></>,
- })}
+ {avatar && !this.props.hideAvatar && showAvatars() && (
+ <PictrsImage src={avatar} icon />
+ )}
<span>{displayName}</span>
</>
);
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
import {
PostResponse,
PurgeItemResponse,
SortType,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
canMod,
capitalizeFirstLetter,
createCommentLikeRes,
isAdmin,
isBanned,
mdToHtml,
+ myAuth,
numToSI,
relTags,
restoreScrollPosition,
import { PersonListing } from "./person-listing";
interface ProfileState {
- personRes: Option<GetPersonDetailsResponse>;
+ personRes?: GetPersonDetailsResponse;
userName: string;
view: PersonDetailsView;
sort: SortType;
page: number;
loading: boolean;
personBlocked: boolean;
- banReason: Option<string>;
- banExpireDays: Option<number>;
+ banReason?: string;
+ banExpireDays?: number;
showBanDialog: boolean;
removeData: boolean;
siteRes: GetSiteResponse;
view: PersonDetailsView;
sort: SortType;
page: number;
- person_id: number | null;
+ person_id?: number;
username: string;
}
}
export class Profile extends Component<any, ProfileState> {
- private isoData = setIsoData(this.context, GetPersonDetailsResponse);
- private subscription: Subscription;
- private emptyState: ProfileState = {
- personRes: None,
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: ProfileState = {
userName: getUsernameFromProps(this.props),
loading: true,
view: Profile.getViewFromProps(this.props.match.view),
personBlocked: false,
siteRes: this.isoData.site_res,
showBanDialog: false,
- banReason: null,
- banExpireDays: null,
removeData: false,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
this.handlePageChange = this.handlePageChange.bind(this);
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- personRes: Some(this.isoData.routeData[0] as GetPersonDetailsResponse),
+ personRes: this.isoData.routeData[0] as GetPersonDetailsResponse,
loading: false,
};
} else {
}
fetchUserData() {
- let form = new GetPersonDetails({
- username: Some(this.state.userName),
- person_id: None,
- community_id: None,
- sort: Some(this.state.sort),
- saved_only: Some(this.state.view === PersonDetailsView.Saved),
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- auth: auth(false).ok(),
- });
+ let form: GetPersonDetails = {
+ username: this.state.userName,
+ sort: this.state.sort,
+ saved_only: this.state.view === PersonDetailsView.Saved,
+ page: this.state.page,
+ limit: fetchLimit,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(wsClient.getPersonDetails(form));
}
get amCurrentUser() {
- return UserService.Instance.myUserInfo.match({
- some: mui =>
- this.state.personRes.match({
- some: res =>
- mui.local_user_view.person.id == res.person_view.person.id,
- none: false,
- }),
- none: false,
- });
+ return (
+ UserService.Instance.myUserInfo?.local_user_view.person.id ==
+ this.state.personRes?.person_view.person.id
+ );
}
setPersonBlock() {
- UserService.Instance.myUserInfo.match({
- some: mui =>
- this.state.personRes.match({
- some: res =>
- this.setState({
- personBlocked: mui.person_blocks
- .map(a => a.target.id)
- .includes(res.person_view.person.id),
- }),
- none: void 0,
- }),
- none: void 0,
- });
+ let mui = UserService.Instance.myUserInfo;
+ let res = this.state.personRes;
+ if (mui && res) {
+ this.setState({
+ personBlocked: mui.person_blocks
+ .map(a => a.target.id)
+ .includes(res.person_view.person.id),
+ });
+ }
}
static getViewFromProps(view: string): PersonDetailsView {
let username = pathSplit[2];
let view = this.getViewFromProps(pathSplit[4]);
- let sort = Some(this.getSortTypeFromProps(pathSplit[6]));
- let page = Some(this.getPageFromProps(Number(pathSplit[8])));
+ let sort = this.getSortTypeFromProps(pathSplit[6]);
+ let page = this.getPageFromProps(Number(pathSplit[8]));
- let form = new GetPersonDetails({
- username: Some(username),
- person_id: None,
- community_id: None,
+ let form: GetPersonDetails = {
+ username: username,
sort,
- saved_only: Some(view === PersonDetailsView.Saved),
+ saved_only: view === PersonDetailsView.Saved,
page,
- limit: Some(fetchLimit),
+ limit: fetchLimit,
auth: req.auth,
- });
+ };
return [req.client.getPersonDetails(form)];
}
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
saveScrollPosition(this.context);
}
view: this.getViewFromProps(props.match.params.view),
sort: this.getSortTypeFromProps(props.match.params.sort),
page: this.getPageFromProps(props.match.params.page),
- person_id: Number(props.match.params.id) || null,
+ person_id: Number(props.match.params.id),
username: props.match.params.username,
};
}
}
get documentTitle(): string {
- return this.state.personRes.match({
- some: res =>
- `@${res.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`,
- none: "",
- });
+ let res = this.state.personRes;
+ return res
+ ? `@${res.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`
+ : "";
}
render() {
+ let res = this.state.personRes;
return (
<div className="container-lg">
{this.state.loading ? (
<Spinner large />
</h5>
) : (
- this.state.personRes.match({
- some: res => (
- <div className="row">
- <div className="col-12 col-md-8">
- <>
- <HtmlTags
- title={this.documentTitle}
- path={this.context.router.route.match.url}
- description={res.person_view.person.bio}
- image={res.person_view.person.avatar}
- />
- {this.userInfo()}
- <hr />
- </>
- {!this.state.loading && this.selects()}
- <PersonDetails
- personRes={res}
- admins={this.state.siteRes.admins}
- sort={this.state.sort}
- page={this.state.page}
- limit={fetchLimit}
- enableDownvotes={enableDownvotes(this.state.siteRes)}
- enableNsfw={enableNsfw(this.state.siteRes)}
- view={this.state.view}
- onPageChange={this.handlePageChange}
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={this.state.siteRes.discussion_languages}
+ res && (
+ <div className="row">
+ <div className="col-12 col-md-8">
+ <>
+ <HtmlTags
+ title={this.documentTitle}
+ path={this.context.router.route.match.url}
+ description={res.person_view.person.bio}
+ image={res.person_view.person.avatar}
/>
- </div>
-
- {!this.state.loading && (
- <div className="col-12 col-md-4">
- {this.moderates()}
- {this.amCurrentUser && this.follows()}
- </div>
- )}
+ {this.userInfo()}
+ <hr />
+ </>
+ {!this.state.loading && this.selects()}
+ <PersonDetails
+ personRes={res}
+ admins={this.state.siteRes.admins}
+ sort={this.state.sort}
+ page={this.state.page}
+ limit={fetchLimit}
+ enableDownvotes={enableDownvotes(this.state.siteRes)}
+ enableNsfw={enableNsfw(this.state.siteRes)}
+ view={this.state.view}
+ onPageChange={this.handlePageChange}
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ />
</div>
- ),
- none: <></>,
- })
+
+ {!this.state.loading && (
+ <div className="col-12 col-md-4">
+ {this.moderates()}
+ {this.amCurrentUser && this.follows()}
+ </div>
+ )}
+ </div>
+ )
)}
</div>
);
);
}
handleBlockPerson(personId: number) {
- if (personId != 0) {
- let blockUserForm = new BlockPerson({
- person_id: personId,
- block: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ let auth = myAuth();
+ if (auth) {
+ if (personId != 0) {
+ let blockUserForm: BlockPerson = {
+ person_id: personId,
+ block: true,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
}
}
handleUnblockPerson(recipientId: number) {
- let blockUserForm = new BlockPerson({
- person_id: recipientId,
- block: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockUserForm: BlockPerson = {
+ person_id: recipientId,
+ block: false,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
}
userInfo() {
- return this.state.personRes
- .map(r => r.person_view)
- .match({
- some: pv => (
- <div>
- <BannerIconHeader
- banner={pv.person.banner}
- icon={pv.person.avatar}
- />
- <div className="mb-3">
- <div className="">
- <div className="mb-0 d-flex flex-wrap">
- <div>
- {pv.person.display_name.match({
- some: displayName => (
- <h5 className="mb-0">{displayName}</h5>
- ),
- none: <></>,
- })}
- <ul className="list-inline mb-2">
- <li className="list-inline-item">
- <PersonListing
- person={pv.person}
- realLink
- useApubName
- muted
- hideAvatar
- />
+ let pv = this.state.personRes?.person_view;
+ return (
+ pv && (
+ <div>
+ <BannerIconHeader banner={pv.person.banner} icon={pv.person.avatar} />
+ <div className="mb-3">
+ <div className="">
+ <div className="mb-0 d-flex flex-wrap">
+ <div>
+ {pv.person.display_name && (
+ <h5 className="mb-0">{pv.person.display_name}</h5>
+ )}
+ <ul className="list-inline mb-2">
+ <li className="list-inline-item">
+ <PersonListing
+ person={pv.person}
+ realLink
+ useApubName
+ muted
+ hideAvatar
+ />
+ </li>
+ {isBanned(pv.person) && (
+ <li className="list-inline-item badge badge-danger">
+ {i18n.t("banned")}
</li>
- {isBanned(pv.person) && (
- <li className="list-inline-item badge badge-danger">
- {i18n.t("banned")}
- </li>
- )}
- {pv.person.deleted && (
- <li className="list-inline-item badge badge-danger">
- {i18n.t("deleted")}
- </li>
- )}
- {pv.person.admin && (
- <li className="list-inline-item badge badge-light">
- {i18n.t("admin")}
- </li>
- )}
- {pv.person.bot_account && (
- <li className="list-inline-item badge badge-light">
- {i18n.t("bot_account").toLowerCase()}
- </li>
- )}
- </ul>
- </div>
- {this.banDialog()}
- <div className="flex-grow-1 unselectable pointer mx-2"></div>
- {!this.amCurrentUser &&
- UserService.Instance.myUserInfo.isSome() && (
- <>
- <a
- className={`d-flex align-self-start btn btn-secondary mr-2 ${
- !pv.person.matrix_user_id && "invisible"
- }`}
- rel={relTags}
- href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
- >
- {i18n.t("send_secure_message")}
- </a>
- <Link
- className={
- "d-flex align-self-start btn btn-secondary mr-2"
- }
- to={`/create_private_message/recipient/${pv.person.id}`}
- >
- {i18n.t("send_message")}
- </Link>
- {this.state.personBlocked ? (
- <button
- className={
- "d-flex align-self-start btn btn-secondary mr-2"
- }
- onClick={linkEvent(
- pv.person.id,
- this.handleUnblockPerson
- )}
- >
- {i18n.t("unblock_user")}
- </button>
- ) : (
- <button
- className={
- "d-flex align-self-start btn btn-secondary mr-2"
- }
- onClick={linkEvent(
- pv.person.id,
- this.handleBlockPerson
- )}
- >
- {i18n.t("block_user")}
- </button>
- )}
- </>
)}
-
- {canMod(
- None,
- Some(this.state.siteRes.admins),
- pv.person.id
- ) &&
- !isAdmin(Some(this.state.siteRes.admins), pv.person.id) &&
- !this.state.showBanDialog &&
- (!isBanned(pv.person) ? (
+ {pv.person.deleted && (
+ <li className="list-inline-item badge badge-danger">
+ {i18n.t("deleted")}
+ </li>
+ )}
+ {pv.person.admin && (
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("admin")}
+ </li>
+ )}
+ {pv.person.bot_account && (
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("bot_account").toLowerCase()}
+ </li>
+ )}
+ </ul>
+ </div>
+ {this.banDialog()}
+ <div className="flex-grow-1 unselectable pointer mx-2"></div>
+ {!this.amCurrentUser && UserService.Instance.myUserInfo && (
+ <>
+ <a
+ className={`d-flex align-self-start btn btn-secondary mr-2 ${
+ !pv.person.matrix_user_id && "invisible"
+ }`}
+ rel={relTags}
+ href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
+ >
+ {i18n.t("send_secure_message")}
+ </a>
+ <Link
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ to={`/create_private_message/recipient/${pv.person.id}`}
+ >
+ {i18n.t("send_message")}
+ </Link>
+ {this.state.personBlocked ? (
<button
className={
"d-flex align-self-start btn btn-secondary mr-2"
}
- onClick={linkEvent(this, this.handleModBanShow)}
- aria-label={i18n.t("ban")}
+ onClick={linkEvent(
+ pv.person.id,
+ this.handleUnblockPerson
+ )}
>
- {capitalizeFirstLetter(i18n.t("ban"))}
+ {i18n.t("unblock_user")}
</button>
) : (
<button
className={
"d-flex align-self-start btn btn-secondary mr-2"
}
- onClick={linkEvent(this, this.handleModBanSubmit)}
- aria-label={i18n.t("unban")}
+ onClick={linkEvent(
+ pv.person.id,
+ this.handleBlockPerson
+ )}
>
- {capitalizeFirstLetter(i18n.t("unban"))}
+ {i18n.t("block_user")}
</button>
- ))}
- </div>
- {pv.person.bio.match({
- some: bio => (
- <div className="d-flex align-items-center mb-2">
- <div
- className="md-div"
- dangerouslySetInnerHTML={mdToHtml(bio)}
- />
- </div>
- ),
- none: <></>,
- })}
- <div>
- <ul className="list-inline mb-2">
- <li className="list-inline-item badge badge-light">
- {i18n.t("number_of_posts", {
- count: pv.counts.post_count,
- formattedCount: numToSI(pv.counts.post_count),
- })}
- </li>
- <li className="list-inline-item badge badge-light">
- {i18n.t("number_of_comments", {
- count: pv.counts.comment_count,
- formattedCount: numToSI(pv.counts.comment_count),
- })}
- </li>
- </ul>
- </div>
- <div className="text-muted">
- {i18n.t("joined")}{" "}
- <MomentTime
- published={pv.person.published}
- updated={None}
- showAgo
- ignoreUpdated
+ )}
+ </>
+ )}
+
+ {canMod(pv.person.id, undefined, this.state.siteRes.admins) &&
+ !isAdmin(pv.person.id, this.state.siteRes.admins) &&
+ !this.state.showBanDialog &&
+ (!isBanned(pv.person) ? (
+ <button
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ onClick={linkEvent(this, this.handleModBanShow)}
+ aria-label={i18n.t("ban")}
+ >
+ {capitalizeFirstLetter(i18n.t("ban"))}
+ </button>
+ ) : (
+ <button
+ className={
+ "d-flex align-self-start btn btn-secondary mr-2"
+ }
+ onClick={linkEvent(this, this.handleModBanSubmit)}
+ aria-label={i18n.t("unban")}
+ >
+ {capitalizeFirstLetter(i18n.t("unban"))}
+ </button>
+ ))}
+ </div>
+ {pv.person.bio && (
+ <div className="d-flex align-items-center mb-2">
+ <div
+ className="md-div"
+ dangerouslySetInnerHTML={mdToHtml(pv.person.bio)}
/>
</div>
- <div className="d-flex align-items-center text-muted mb-2">
- <Icon icon="cake" />
- <span className="ml-2">
- {i18n.t("cake_day_title")}{" "}
- {moment
- .utc(pv.person.published)
- .local()
- .format("MMM DD, YYYY")}
- </span>
- </div>
+ )}
+ <div>
+ <ul className="list-inline mb-2">
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("number_of_posts", {
+ count: pv.counts.post_count,
+ formattedCount: numToSI(pv.counts.post_count),
+ })}
+ </li>
+ <li className="list-inline-item badge badge-light">
+ {i18n.t("number_of_comments", {
+ count: pv.counts.comment_count,
+ formattedCount: numToSI(pv.counts.comment_count),
+ })}
+ </li>
+ </ul>
+ </div>
+ <div className="text-muted">
+ {i18n.t("joined")}{" "}
+ <MomentTime
+ published={pv.person.published}
+ showAgo
+ ignoreUpdated
+ />
+ </div>
+ <div className="d-flex align-items-center text-muted mb-2">
+ <Icon icon="cake" />
+ <span className="ml-2">
+ {i18n.t("cake_day_title")}{" "}
+ {moment
+ .utc(pv.person.published)
+ .local()
+ .format("MMM DD, YYYY")}
+ </span>
</div>
</div>
</div>
- ),
- none: <></>,
- });
+ </div>
+ )
+ );
}
banDialog() {
- return this.state.personRes
- .map(r => r.person_view)
- .match({
- some: pv => (
- <>
- {this.state.showBanDialog && (
- <form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
- <div className="form-group row col-12">
- <label
- className="col-form-label"
- htmlFor="profile-ban-reason"
- >
- {i18n.t("reason")}
- </label>
- <input
- type="text"
- id="profile-ban-reason"
- className="form-control mr-2"
- placeholder={i18n.t("reason")}
- value={toUndefined(this.state.banReason)}
- onInput={linkEvent(this, this.handleModBanReasonChange)}
- />
- <label className="col-form-label" htmlFor={`mod-ban-expires`}>
- {i18n.t("expires")}
- </label>
- <input
- type="number"
- id={`mod-ban-expires`}
- className="form-control mr-2"
- placeholder={i18n.t("number_of_days")}
- value={toUndefined(this.state.banExpireDays)}
- onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
- />
- <div className="form-group">
- <div className="form-check">
- <input
- className="form-check-input"
- id="mod-ban-remove-data"
- type="checkbox"
- checked={this.state.removeData}
- onChange={linkEvent(
- this,
- this.handleModRemoveDataChange
- )}
- />
- <label
- className="form-check-label"
- htmlFor="mod-ban-remove-data"
- title={i18n.t("remove_content_more")}
- >
- {i18n.t("remove_content")}
- </label>
- </div>
+ let pv = this.state.personRes?.person_view;
+ return (
+ pv && (
+ <>
+ {this.state.showBanDialog && (
+ <form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
+ <div className="form-group row col-12">
+ <label className="col-form-label" htmlFor="profile-ban-reason">
+ {i18n.t("reason")}
+ </label>
+ <input
+ type="text"
+ id="profile-ban-reason"
+ className="form-control mr-2"
+ placeholder={i18n.t("reason")}
+ value={this.state.banReason}
+ onInput={linkEvent(this, this.handleModBanReasonChange)}
+ />
+ <label className="col-form-label" htmlFor={`mod-ban-expires`}>
+ {i18n.t("expires")}
+ </label>
+ <input
+ type="number"
+ id={`mod-ban-expires`}
+ className="form-control mr-2"
+ placeholder={i18n.t("number_of_days")}
+ value={this.state.banExpireDays}
+ onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
+ />
+ <div className="form-group">
+ <div className="form-check">
+ <input
+ className="form-check-input"
+ id="mod-ban-remove-data"
+ type="checkbox"
+ checked={this.state.removeData}
+ onChange={linkEvent(this, this.handleModRemoveDataChange)}
+ />
+ <label
+ className="form-check-label"
+ htmlFor="mod-ban-remove-data"
+ title={i18n.t("remove_content_more")}
+ >
+ {i18n.t("remove_content")}
+ </label>
</div>
</div>
- {/* TODO hold off on expires until later */}
- {/* <div class="form-group row"> */}
- {/* <label class="col-form-label">Expires</label> */}
- {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
- {/* </div> */}
- <div className="form-group row">
- <button
- type="reset"
- className="btn btn-secondary mr-2"
- aria-label={i18n.t("cancel")}
- onClick={linkEvent(this, this.handleModBanSubmitCancel)}
- >
- {i18n.t("cancel")}
- </button>
- <button
- type="submit"
- className="btn btn-secondary"
- aria-label={i18n.t("ban")}
- >
- {i18n.t("ban")} {pv.person.name}
- </button>
- </div>
- </form>
- )}
- </>
- ),
- none: <></>,
- });
+ </div>
+ {/* TODO hold off on expires until later */}
+ {/* <div class="form-group row"> */}
+ {/* <label class="col-form-label">Expires</label> */}
+ {/* <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
+ {/* </div> */}
+ <div className="form-group row">
+ <button
+ type="reset"
+ className="btn btn-secondary mr-2"
+ aria-label={i18n.t("cancel")}
+ onClick={linkEvent(this, this.handleModBanSubmitCancel)}
+ >
+ {i18n.t("cancel")}
+ </button>
+ <button
+ type="submit"
+ className="btn btn-secondary"
+ aria-label={i18n.t("ban")}
+ >
+ {i18n.t("ban")} {pv.person.name}
+ </button>
+ </div>
+ </form>
+ )}
+ </>
+ )
+ );
}
moderates() {
- return this.state.personRes
- .map(r => r.moderates)
- .match({
- some: moderates => {
- if (moderates.length > 0) {
- return (
- <div className="card border-secondary mb-3">
- <div className="card-body">
- <h5>{i18n.t("moderates")}</h5>
- <ul className="list-unstyled mb-0">
- {moderates.map(cmv => (
- <li key={cmv.community.id}>
- <CommunityLink community={cmv.community} />
- </li>
- ))}
- </ul>
- </div>
- </div>
- );
- } else {
- return <></>;
- }
- },
- none: void 0,
- });
+ let moderates = this.state.personRes?.moderates;
+ return (
+ moderates &&
+ moderates.length > 0 && (
+ <div className="card border-secondary mb-3">
+ <div className="card-body">
+ <h5>{i18n.t("moderates")}</h5>
+ <ul className="list-unstyled mb-0">
+ {moderates.map(cmv => (
+ <li key={cmv.community.id}>
+ <CommunityLink community={cmv.community} />
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ )
+ );
}
follows() {
- return UserService.Instance.myUserInfo
- .map(m => m.follows)
- .match({
- some: follows => {
- if (follows.length > 0) {
- return (
- <div className="card border-secondary mb-3">
- <div className="card-body">
- <h5>{i18n.t("subscribed")}</h5>
- <ul className="list-unstyled mb-0">
- {follows.map(cfv => (
- <li key={cfv.community.id}>
- <CommunityLink community={cfv.community} />
- </li>
- ))}
- </ul>
- </div>
- </div>
- );
- } else {
- return <></>;
- }
- },
- none: void 0,
- });
+ let follows = UserService.Instance.myUserInfo?.follows;
+ return (
+ follows &&
+ follows.length > 0 && (
+ <div className="card border-secondary mb-3">
+ <div className="card-body">
+ <h5>{i18n.t("subscribed")}</h5>
+ <ul className="list-unstyled mb-0">
+ {follows.map(cfv => (
+ <li key={cfv.community.id}>
+ <CommunityLink community={cfv.community} />
+ </li>
+ ))}
+ </ul>
+ </div>
+ </div>
+ )
+ );
}
updateUrl(paramUpdates: UrlParams) {
handleModBanSubmit(i: Profile, event?: any) {
if (event) event.preventDefault();
+ let person = i.state.personRes?.person_view.person;
+ let auth = myAuth();
+ if (person && auth) {
+ // If its an unban, restore all their data
+ let ban = !person.banned;
+ if (ban == false) {
+ i.setState({ removeData: false });
+ }
+ let form: BanPerson = {
+ person_id: person.id,
+ ban,
+ remove_data: i.state.removeData,
+ reason: i.state.banReason,
+ expires: futureDaysToUnixTime(i.state.banExpireDays),
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.banPerson(form));
- i.state.personRes
- .map(r => r.person_view.person)
- .match({
- some: person => {
- // If its an unban, restore all their data
- let ban = !person.banned;
- if (ban == false) {
- i.setState({ removeData: false });
- }
- let form = new BanPerson({
- person_id: person.id,
- ban,
- remove_data: Some(i.state.removeData),
- reason: i.state.banReason,
- expires: i.state.banExpireDays.map(futureDaysToUnixTime),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.banPerson(form));
-
- i.setState({ showBanDialog: false });
- },
- none: void 0,
- });
+ i.setState({ showBanDialog: false });
+ }
}
parseMessage(msg: any) {
// Since the PersonDetails contains posts/comments as well as some general user info we listen here as well
// and set the parent state if it is not set or differs
// TODO this might need to get abstracted
- let data = wsJsonToRes<GetPersonDetailsResponse>(
- msg,
- GetPersonDetailsResponse
- );
- this.setState({ personRes: Some(data), loading: false });
+ let data = wsJsonToRes<GetPersonDetailsResponse>(msg);
+ this.setState({ personRes: data, loading: false });
this.setPersonBlock();
restoreScrollPosition(this.context);
} else if (op == UserOperation.AddAdmin) {
- let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
+ let data = wsJsonToRes<AddAdminResponse>(msg);
this.setState(s => ((s.siteRes.admins = data.admins), s));
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- createCommentLikeRes(
- data.comment_view,
- this.state.personRes.map(r => r.comments).unwrapOr([])
- );
+ let data = wsJsonToRes<CommentResponse>(msg);
+ createCommentLikeRes(data.comment_view, this.state.personRes?.comments);
this.setState(this.state);
} else if (
op == UserOperation.EditComment ||
op == UserOperation.DeleteComment ||
op == UserOperation.RemoveComment
) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- editCommentRes(
- data.comment_view,
- this.state.personRes.map(r => r.comments).unwrapOr([])
- );
+ let data = wsJsonToRes<CommentResponse>(msg);
+ editCommentRes(data.comment_view, this.state.personRes?.comments);
this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- UserService.Instance.myUserInfo.match({
- some: mui => {
- if (data.comment_view.creator.id == mui.local_user_view.person.id) {
- toast(i18n.t("reply_sent"));
- }
- },
- none: void 0,
- });
+ let data = wsJsonToRes<CommentResponse>(msg);
+ let mui = UserService.Instance.myUserInfo;
+ if (data.comment_view.creator.id == mui?.local_user_view.person.id) {
+ toast(i18n.t("reply_sent"));
+ }
} else if (op == UserOperation.SaveComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- saveCommentRes(
- data.comment_view,
- this.state.personRes.map(r => r.comments).unwrapOr([])
- );
+ let data = wsJsonToRes<CommentResponse>(msg);
+ saveCommentRes(data.comment_view, this.state.personRes?.comments);
this.setState(this.state);
} else if (
op == UserOperation.EditPost ||
op == UserOperation.FeaturePost ||
op == UserOperation.SavePost
) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- editPostFindRes(
- data.post_view,
- this.state.personRes.map(r => r.posts).unwrapOr([])
- );
+ let data = wsJsonToRes<PostResponse>(msg);
+ editPostFindRes(data.post_view, this.state.personRes?.posts);
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- createPostLikeFindRes(
- data.post_view,
- this.state.personRes.map(r => r.posts).unwrapOr([])
- );
+ let data = wsJsonToRes<PostResponse>(msg);
+ createPostLikeFindRes(data.post_view, this.state.personRes?.posts);
this.setState(this.state);
} else if (op == UserOperation.BanPerson) {
- let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
- this.state.personRes.match({
- some: res => {
- res.comments
- .filter(c => c.creator.id == data.person_view.person.id)
- .forEach(c => (c.creator.banned = data.banned));
- res.posts
- .filter(c => c.creator.id == data.person_view.person.id)
- .forEach(c => (c.creator.banned = data.banned));
- let pv = res.person_view;
-
- if (pv.person.id == data.person_view.person.id) {
- pv.person.banned = data.banned;
- }
- this.setState(this.state);
- },
- none: void 0,
- });
+ let data = wsJsonToRes<BanPersonResponse>(msg);
+ let res = this.state.personRes;
+ res?.comments
+ .filter(c => c.creator.id == data.person_view.person.id)
+ .forEach(c => (c.creator.banned = data.banned));
+ res?.posts
+ .filter(c => c.creator.id == data.person_view.person.id)
+ .forEach(c => (c.creator.banned = data.banned));
+ let pv = res?.person_view;
+
+ if (pv?.person.id == data.person_view.person.id) {
+ pv.person.banned = data.banned;
+ }
+ this.setState(this.state);
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
+ let data = wsJsonToRes<BlockPersonResponse>(msg);
updatePersonBlock(data);
this.setPersonBlock();
this.setState(this.state);
op == UserOperation.PurgeComment ||
op == UserOperation.PurgeCommunity
) {
- let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+ let data = wsJsonToRes<PurgeItemResponse>(msg);
if (data.success) {
toast(i18n.t("purge_success"));
this.context.router.history.push(`/`);
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
GetSiteResponse,
import { InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
fetchLimit,
isBrowser,
+ myAuth,
setIsoData,
setupTippy,
toast,
}
interface RegistrationApplicationsState {
- listRegistrationApplicationsResponse: Option<ListRegistrationApplicationsResponse>;
+ listRegistrationApplicationsResponse?: ListRegistrationApplicationsResponse;
siteRes: GetSiteResponse;
unreadOrAll: UnreadOrAll;
page: number;
any,
RegistrationApplicationsState
> {
- private isoData = setIsoData(
- this.context,
- ListRegistrationApplicationsResponse
- );
- private subscription: Subscription;
- private emptyState: RegistrationApplicationsState = {
- listRegistrationApplicationsResponse: None,
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: RegistrationApplicationsState = {
siteRes: this.isoData.site_res,
unreadOrAll: UnreadOrAll.Unread,
page: 1,
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePageChange = this.handlePageChange.bind(this);
- if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+ if (!UserService.Instance.myUserInfo && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`);
}
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- listRegistrationApplicationsResponse: Some(
- this.isoData.routeData[0] as ListRegistrationApplicationsResponse
- ),
+ listRegistrationApplicationsResponse: this.isoData
+ .routeData[0] as ListRegistrationApplicationsResponse,
loading: false,
};
} else {
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
get documentTitle(): string {
- return UserService.Instance.myUserInfo.match({
- some: mui =>
- `@${mui.local_user_view.person.name} ${i18n.t(
+ let mui = UserService.Instance.myUserInfo;
+ return mui
+ ? `@${mui.local_user_view.person.name} ${i18n.t(
"registration_applications"
- )} - ${this.state.siteRes.site_view.site.name}`,
- none: "",
- });
+ )} - ${this.state.siteRes.site_view.site.name}`
+ : "";
}
render() {
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<h5 className="mb-2">{i18n.t("registration_applications")}</h5>
{this.selects()}
}
applicationList() {
- return this.state.listRegistrationApplicationsResponse.match({
- some: res => (
+ let res = this.state.listRegistrationApplicationsResponse;
+ return (
+ res && (
<div>
{res.registration_applications.map(ra => (
<>
</>
))}
</div>
- ),
- none: <></>,
- });
+ )
+ );
}
handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let promises: Promise<any>[] = [];
- let form = new ListRegistrationApplications({
- unread_only: Some(true),
- page: Some(1),
- limit: Some(fetchLimit),
- auth: req.auth.unwrap(),
- });
- promises.push(req.client.listRegistrationApplications(form));
+ let auth = req.auth;
+ if (auth) {
+ let form: ListRegistrationApplications = {
+ unread_only: true,
+ page: 1,
+ limit: fetchLimit,
+ auth,
+ };
+ promises.push(req.client.listRegistrationApplications(form));
+ }
return promises;
}
refetch() {
let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread;
- let form = new ListRegistrationApplications({
- unread_only: Some(unread_only),
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.listRegistrationApplications(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: ListRegistrationApplications = {
+ unread_only: unread_only,
+ page: this.state.page,
+ limit: fetchLimit,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.listRegistrationApplications(form)
+ );
+ }
}
parseMessage(msg: any) {
} else if (msg.reconnect) {
this.refetch();
} else if (op == UserOperation.ListRegistrationApplications) {
- let data = wsJsonToRes<ListRegistrationApplicationsResponse>(
- msg,
- ListRegistrationApplicationsResponse
- );
+ let data = wsJsonToRes<ListRegistrationApplicationsResponse>(msg);
this.setState({
- listRegistrationApplicationsResponse: Some(data),
+ listRegistrationApplicationsResponse: data,
loading: false,
});
window.scrollTo(0, 0);
} else if (op == UserOperation.ApproveRegistrationApplication) {
- let data = wsJsonToRes<RegistrationApplicationResponse>(
- msg,
- RegistrationApplicationResponse
- );
+ let data = wsJsonToRes<RegistrationApplicationResponse>(msg);
updateRegistrationApplicationRes(
data.registration_application,
this.state.listRegistrationApplicationsResponse
- .map(r => r.registration_applications)
- .unwrapOr([])
+ ?.registration_applications
);
let uacs = UserService.Instance.unreadApplicationCountSub;
// Minor bug, where if the application switches from deny to approve, the count will still go down
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
CommentReportResponse,
import { UserService, WebSocketService } from "../../services";
import {
amAdmin,
- auth,
fetchLimit,
isBrowser,
+ myAuth,
setIsoData,
setupTippy,
toast,
};
interface ReportsState {
- listCommentReportsResponse: Option<ListCommentReportsResponse>;
- listPostReportsResponse: Option<ListPostReportsResponse>;
- listPrivateMessageReportsResponse: Option<ListPrivateMessageReportsResponse>;
+ listCommentReportsResponse?: ListCommentReportsResponse;
+ listPostReportsResponse?: ListPostReportsResponse;
+ listPrivateMessageReportsResponse?: ListPrivateMessageReportsResponse;
unreadOrAll: UnreadOrAll;
messageType: MessageType;
combined: ItemType[];
}
export class Reports extends Component<any, ReportsState> {
- private isoData = setIsoData(
- this.context,
- ListCommentReportsResponse,
- ListPostReportsResponse,
- ListPrivateMessageReportsResponse
- );
- private subscription: Subscription;
- private emptyState: ReportsState = {
- listCommentReportsResponse: None,
- listPostReportsResponse: None,
- listPrivateMessageReportsResponse: None,
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: ReportsState = {
unreadOrAll: UnreadOrAll.Unread,
messageType: MessageType.All,
combined: [],
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePageChange = this.handlePageChange.bind(this);
- if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+ if (!UserService.Instance.myUserInfo && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`);
}
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- listCommentReportsResponse: Some(
- this.isoData.routeData[0] as ListCommentReportsResponse
- ),
- listPostReportsResponse: Some(
- this.isoData.routeData[1] as ListPostReportsResponse
- ),
+ listCommentReportsResponse: this.isoData
+ .routeData[0] as ListCommentReportsResponse,
+ listPostReportsResponse: this.isoData
+ .routeData[1] as ListPostReportsResponse,
};
if (amAdmin()) {
this.state = {
...this.state,
- listPrivateMessageReportsResponse: Some(
- this.isoData.routeData[2] as ListPrivateMessageReportsResponse
- ),
+ listPrivateMessageReportsResponse: this.isoData
+ .routeData[2] as ListPrivateMessageReportsResponse,
};
}
this.state = {
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
get documentTitle(): string {
- return UserService.Instance.myUserInfo.match({
- some: mui =>
- `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
+ let mui = UserService.Instance.myUserInfo;
+ return mui
+ ? `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
this.state.siteRes.site_view.site.name
- }`,
- none: "",
- });
+ }`
+ : "";
}
render() {
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<h5 className="mb-2">{i18n.t("reports")}</h5>
{this.selects()}
}
buildCombined(): ItemType[] {
- let comments: ItemType[] = this.state.listCommentReportsResponse
- .map(r => r.comment_reports)
- .unwrapOr([])
- .map(r => this.commentReportToItemType(r));
- let posts: ItemType[] = this.state.listPostReportsResponse
- .map(r => r.post_reports)
- .unwrapOr([])
- .map(r => this.postReportToItemType(r));
- let privateMessages: ItemType[] =
- this.state.listPrivateMessageReportsResponse
- .map(r => r.private_message_reports)
- .unwrapOr([])
- .map(r => this.privateMessageReportToItemType(r));
+ // let comments: ItemType[] = this.state.listCommentReportsResponse
+ // .map(r => r.comment_reports)
+ // .unwrapOr([])
+ // .map(r => this.commentReportToItemType(r));
+ let comments =
+ this.state.listCommentReportsResponse?.comment_reports.map(
+ this.commentReportToItemType
+ ) ?? [];
+ let posts =
+ this.state.listPostReportsResponse?.post_reports.map(
+ this.postReportToItemType
+ ) ?? [];
+ let privateMessages =
+ this.state.listPrivateMessageReportsResponse?.private_message_reports.map(
+ this.privateMessageReportToItemType
+ ) ?? [];
return [...comments, ...posts, ...privateMessages].sort((a, b) =>
b.published.localeCompare(a.published)
}
commentReports() {
- return this.state.listCommentReportsResponse.match({
- some: res => (
+ let reports = this.state.listCommentReportsResponse?.comment_reports;
+ return (
+ reports && (
<div>
- {res.comment_reports.map(cr => (
+ {reports.map(cr => (
<>
<hr />
<CommentReport key={cr.comment_report.id} report={cr} />
</>
))}
</div>
- ),
- none: <></>,
- });
+ )
+ );
}
postReports() {
- return this.state.listPostReportsResponse.match({
- some: res => (
+ let reports = this.state.listPostReportsResponse?.post_reports;
+ return (
+ reports && (
<div>
- {res.post_reports.map(pr => (
+ {reports.map(pr => (
<>
<hr />
<PostReport key={pr.post_report.id} report={pr} />
</>
))}
</div>
- ),
- none: <></>,
- });
+ )
+ );
}
privateMessageReports() {
- return this.state.listPrivateMessageReportsResponse.match({
- some: res => (
+ let reports =
+ this.state.listPrivateMessageReportsResponse?.private_message_reports;
+ return (
+ reports && (
<div>
- {res.private_message_reports.map(pmr => (
+ {reports.map(pmr => (
<>
<hr />
<PrivateMessageReport
</>
))}
</div>
- ),
- none: <></>,
- });
+ )
+ );
}
handlePageChange(page: number) {
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let promises: Promise<any>[] = [];
- let unresolved_only = Some(true);
- let page = Some(1);
- let limit = Some(fetchLimit);
- let community_id = None;
- let auth = req.auth.unwrap();
-
- let commentReportsForm = new ListCommentReports({
- // TODO community_id
- unresolved_only,
- community_id,
- page,
- limit,
- auth,
- });
- promises.push(req.client.listCommentReports(commentReportsForm));
-
- let postReportsForm = new ListPostReports({
- // TODO community_id
- unresolved_only,
- community_id,
- page,
- limit,
- auth,
- });
- promises.push(req.client.listPostReports(postReportsForm));
-
- if (amAdmin()) {
- let privateMessageReportsForm = new ListPrivateMessageReports({
+ let unresolved_only = true;
+ let page = 1;
+ let limit = fetchLimit;
+ let auth = req.auth;
+
+ if (auth) {
+ let commentReportsForm: ListCommentReports = {
unresolved_only,
page,
limit,
auth,
- });
- promises.push(
- req.client.listPrivateMessageReports(privateMessageReportsForm)
- );
+ };
+ promises.push(req.client.listCommentReports(commentReportsForm));
+
+ let postReportsForm: ListPostReports = {
+ unresolved_only,
+ page,
+ limit,
+ auth,
+ };
+ promises.push(req.client.listPostReports(postReportsForm));
+
+ if (amAdmin()) {
+ let privateMessageReportsForm: ListPrivateMessageReports = {
+ unresolved_only,
+ page,
+ limit,
+ auth,
+ };
+ promises.push(
+ req.client.listPrivateMessageReports(privateMessageReportsForm)
+ );
+ }
}
return promises;
}
refetch() {
- let unresolved_only = Some(this.state.unreadOrAll == UnreadOrAll.Unread);
- let community_id = None;
- let page = Some(this.state.page);
- let limit = Some(fetchLimit);
-
- let commentReportsForm = new ListCommentReports({
- unresolved_only,
- // TODO community_id
- community_id,
- page,
- limit,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(
- wsClient.listCommentReports(commentReportsForm)
- );
-
- let postReportsForm = new ListPostReports({
- unresolved_only,
- // TODO community_id
- community_id,
- page,
- limit,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.listPostReports(postReportsForm));
-
- if (amAdmin()) {
- let privateMessageReportsForm = new ListPrivateMessageReports({
+ let unresolved_only = this.state.unreadOrAll == UnreadOrAll.Unread;
+ let page = this.state.page;
+ let limit = fetchLimit;
+ let auth = myAuth();
+ if (auth) {
+ let commentReportsForm: ListCommentReports = {
unresolved_only,
page,
limit,
- auth: auth().unwrap(),
- });
+ auth,
+ };
WebSocketService.Instance.send(
- wsClient.listPrivateMessageReports(privateMessageReportsForm)
+ wsClient.listCommentReports(commentReportsForm)
);
+
+ let postReportsForm: ListPostReports = {
+ unresolved_only,
+ page,
+ limit,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.listPostReports(postReportsForm));
+
+ if (amAdmin()) {
+ let privateMessageReportsForm: ListPrivateMessageReports = {
+ unresolved_only,
+ page,
+ limit,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.listPrivateMessageReports(privateMessageReportsForm)
+ );
+ }
}
}
} else if (msg.reconnect) {
this.refetch();
} else if (op == UserOperation.ListCommentReports) {
- let data = wsJsonToRes<ListCommentReportsResponse>(
- msg,
- ListCommentReportsResponse
- );
- this.setState({ listCommentReportsResponse: Some(data) });
+ let data = wsJsonToRes<ListCommentReportsResponse>(msg);
+ this.setState({ listCommentReportsResponse: data });
this.setState({ combined: this.buildCombined(), loading: false });
// this.sendUnreadCount();
window.scrollTo(0, 0);
setupTippy();
} else if (op == UserOperation.ListPostReports) {
- let data = wsJsonToRes<ListPostReportsResponse>(
- msg,
- ListPostReportsResponse
- );
- this.setState({ listPostReportsResponse: Some(data) });
+ let data = wsJsonToRes<ListPostReportsResponse>(msg);
+ this.setState({ listPostReportsResponse: data });
this.setState({ combined: this.buildCombined(), loading: false });
// this.sendUnreadCount();
window.scrollTo(0, 0);
setupTippy();
} else if (op == UserOperation.ListPrivateMessageReports) {
- let data = wsJsonToRes<ListPrivateMessageReportsResponse>(
- msg,
- ListPrivateMessageReportsResponse
- );
- this.setState({ listPrivateMessageReportsResponse: Some(data) });
+ let data = wsJsonToRes<ListPrivateMessageReportsResponse>(msg);
+ this.setState({ listPrivateMessageReportsResponse: data });
this.setState({ combined: this.buildCombined(), loading: false });
// this.sendUnreadCount();
window.scrollTo(0, 0);
setupTippy();
} else if (op == UserOperation.ResolvePostReport) {
- let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+ let data = wsJsonToRes<PostReportResponse>(msg);
updatePostReportRes(
data.post_report_view,
- this.state.listPostReportsResponse.map(r => r.post_reports).unwrapOr([])
+ this.state.listPostReportsResponse?.post_reports
);
let urcs = UserService.Instance.unreadReportCountSub;
if (data.post_report_view.post_report.resolved) {
}
this.setState(this.state);
} else if (op == UserOperation.ResolveCommentReport) {
- let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+ let data = wsJsonToRes<CommentReportResponse>(msg);
updateCommentReportRes(
data.comment_report_view,
- this.state.listCommentReportsResponse
- .map(r => r.comment_reports)
- .unwrapOr([])
+ this.state.listCommentReportsResponse?.comment_reports
);
let urcs = UserService.Instance.unreadReportCountSub;
if (data.comment_report_view.comment_report.resolved) {
}
this.setState(this.state);
} else if (op == UserOperation.ResolvePrivateMessageReport) {
- let data = wsJsonToRes<PrivateMessageReportResponse>(
- msg,
- PrivateMessageReportResponse
- );
+ let data = wsJsonToRes<PrivateMessageReportResponse>(msg);
updatePrivateMessageReportRes(
data.private_message_report_view,
- this.state.listPrivateMessageReportsResponse
- .map(r => r.private_message_reports)
- .unwrapOr([])
+ this.state.listPrivateMessageReportsResponse?.private_message_reports
);
let urcs = UserService.Instance.unreadReportCountSub;
if (data.private_message_report_view.private_message_report.resolved) {
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
BlockCommunity,
PersonViewSafe,
SaveUserSettings,
SortType,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
import { i18n, languages } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
capitalizeFirstLetter,
choicesConfig,
communitySelectName,
fetchUsers,
getLanguages,
isBrowser,
+ myAuth,
personSelectName,
personToChoice,
relTags,
}
interface SettingsState {
- saveUserSettingsForm: SaveUserSettings;
- changePasswordForm: ChangePassword;
- deleteAccountForm: DeleteAccount;
+ // TODO redo these forms
+ saveUserSettingsForm: {
+ show_nsfw?: boolean;
+ theme?: string;
+ default_sort_type?: number;
+ default_listing_type?: number;
+ interface_language?: string;
+ avatar?: string;
+ banner?: string;
+ display_name?: string;
+ email?: string;
+ bio?: string;
+ matrix_user_id?: string;
+ show_avatars?: boolean;
+ show_scores?: boolean;
+ send_notifications_to_email?: boolean;
+ bot_account?: boolean;
+ show_bot_accounts?: boolean;
+ show_read_posts?: boolean;
+ show_new_post_notifs?: boolean;
+ discussion_languages?: number[];
+ };
+ changePasswordForm: {
+ new_password?: string;
+ new_password_verify?: string;
+ old_password?: string;
+ };
+ deleteAccountForm: {
+ password?: string;
+ };
personBlocks: PersonBlockView[];
- blockPerson: Option<PersonViewSafe>;
+ blockPerson?: PersonViewSafe;
communityBlocks: CommunityBlockView[];
blockCommunityId: number;
blockCommunity?: CommunityView;
private isoData = setIsoData(this.context);
private blockPersonChoices: any;
private blockCommunityChoices: any;
- private subscription: Subscription;
- private emptyState: SettingsState = {
- saveUserSettingsForm: new SaveUserSettings({
- show_nsfw: None,
- show_scores: None,
- show_avatars: None,
- show_read_posts: None,
- show_bot_accounts: None,
- show_new_post_notifs: None,
- default_sort_type: None,
- default_listing_type: None,
- theme: None,
- interface_language: None,
- discussion_languages: None,
- avatar: None,
- banner: None,
- display_name: None,
- email: None,
- bio: None,
- matrix_user_id: None,
- send_notifications_to_email: None,
- bot_account: None,
- auth: undefined,
- }),
- changePasswordForm: new ChangePassword({
- new_password: undefined,
- new_password_verify: undefined,
- old_password: undefined,
- auth: undefined,
- }),
+ private subscription?: Subscription;
+ state: SettingsState = {
+ saveUserSettingsForm: {},
+ changePasswordForm: {},
saveUserSettingsLoading: false,
changePasswordLoading: false,
deleteAccountLoading: false,
deleteAccountShowConfirm: false,
- deleteAccountForm: new DeleteAccount({
- password: undefined,
- auth: undefined,
- }),
+ deleteAccountForm: {},
personBlocks: [],
- blockPerson: None,
communityBlocks: [],
blockCommunityId: 0,
currentTab: "settings",
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSortTypeChange = this.handleSortTypeChange.bind(this);
this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
this.handleBioChange = this.handleBioChange.bind(this);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
- if (UserService.Instance.myUserInfo.isSome()) {
- let mui = UserService.Instance.myUserInfo.unwrap();
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
let luv = mui.local_user_view;
this.state = {
...this.state,
communityBlocks: mui.community_blocks,
saveUserSettingsForm: {
...this.state.saveUserSettingsForm,
- show_nsfw: Some(luv.local_user.show_nsfw),
- theme: Some(luv.local_user.theme ? luv.local_user.theme : "browser"),
- default_sort_type: Some(luv.local_user.default_sort_type),
- default_listing_type: Some(luv.local_user.default_listing_type),
- interface_language: Some(luv.local_user.interface_language),
- discussion_languages: Some(mui.discussion_languages),
+ show_nsfw: luv.local_user.show_nsfw,
+ theme: luv.local_user.theme ? luv.local_user.theme : "browser",
+ default_sort_type: luv.local_user.default_sort_type,
+ default_listing_type: luv.local_user.default_listing_type,
+ interface_language: luv.local_user.interface_language,
+ discussion_languages: mui.discussion_languages,
avatar: luv.person.avatar,
banner: luv.person.banner,
display_name: luv.person.display_name,
- show_avatars: Some(luv.local_user.show_avatars),
- bot_account: Some(luv.person.bot_account),
- show_bot_accounts: Some(luv.local_user.show_bot_accounts),
- show_scores: Some(luv.local_user.show_scores),
- show_read_posts: Some(luv.local_user.show_read_posts),
- show_new_post_notifs: Some(luv.local_user.show_new_post_notifs),
+ show_avatars: luv.local_user.show_avatars,
+ bot_account: luv.person.bot_account,
+ show_bot_accounts: luv.local_user.show_bot_accounts,
+ show_scores: luv.local_user.show_scores,
+ show_read_posts: luv.local_user.show_read_posts,
+ show_new_post_notifs: luv.local_user.show_new_post_notifs,
email: luv.local_user.email,
bio: luv.person.bio,
- send_notifications_to_email: Some(
- luv.local_user.send_notifications_to_email
- ),
+ send_notifications_to_email:
+ luv.local_user.send_notifications_to_email,
matrix_user_id: luv.person.matrix_user_id,
},
};
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
get documentTitle(): string {
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={Some(this.documentTitle)}
+ description={this.documentTitle}
image={this.state.saveUserSettingsForm.avatar}
/>
<ul className="nav nav-tabs mb-2">
}
blockUserForm() {
+ let blockPerson = this.state.blockPerson;
return (
<div className="form-group row">
<label
<select
className="form-control"
id="block-person-filter"
- value={this.state.blockPerson.map(p => p.person.id).unwrapOr(0)}
+ value={blockPerson?.person.id ?? 0}
>
<option value="0">—</option>
- {this.state.blockPerson.match({
- some: personView => (
- <option value={personView.person.id}>
- {personSelectName(personView)}
- </option>
- ),
- none: <></>,
- })}
+ {blockPerson && (
+ <option value={blockPerson.person.id}>
+ {personSelectName(blockPerson)}
+ </option>
+ )}
</select>
</div>
</div>
type="text"
className="form-control"
placeholder={i18n.t("optional")}
- value={toUndefined(
- this.state.saveUserSettingsForm.display_name
- )}
+ value={this.state.saveUserSettingsForm.display_name}
onInput={linkEvent(this, this.handleDisplayNameChange)}
pattern="^(?!@)(.+)$"
minLength={3}
<div className="col-sm-9">
<MarkdownTextArea
initialContent={this.state.saveUserSettingsForm.bio}
- initialLanguageId={None}
onContentChange={this.handleBioChange}
- maxLength={Some(300)}
- placeholder={None}
- buttonTitle={None}
+ maxLength={300}
hideNavigationWarnings
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
id="user-email"
className="form-control"
placeholder={i18n.t("optional")}
- value={toUndefined(this.state.saveUserSettingsForm.email)}
+ value={this.state.saveUserSettingsForm.email}
onInput={linkEvent(this, this.handleEmailChange)}
minLength={3}
/>
type="text"
className="form-control"
placeholder="@user:example.com"
- value={toUndefined(
- this.state.saveUserSettingsForm.matrix_user_id
- )}
+ value={this.state.saveUserSettingsForm.matrix_user_id}
onInput={linkEvent(this, this.handleMatrixUserIdChange)}
pattern="^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
/>
<div className="col-sm-9">
<select
id="user-language"
- value={toUndefined(
- this.state.saveUserSettingsForm.interface_language
- )}
+ value={this.state.saveUserSettingsForm.interface_language}
onChange={linkEvent(this, this.handleInterfaceLangChange)}
className="custom-select w-auto"
>
<div className="col-sm-9">
<select
id="user-theme"
- value={toUndefined(this.state.saveUserSettingsForm.theme)}
+ value={this.state.saveUserSettingsForm.theme}
onChange={linkEvent(this, this.handleThemeChange)}
className="custom-select w-auto"
>
<ListingTypeSelect
type_={
Object.values(ListingType)[
- this.state.saveUserSettingsForm.default_listing_type.unwrapOr(
- 1
- )
+ this.state.saveUserSettingsForm.default_listing_type ?? 1
]
}
showLocal={showLocal(this.isoData)}
<SortSelect
sort={
Object.values(SortType)[
- this.state.saveUserSettingsForm.default_sort_type.unwrapOr(
- 0
- )
+ this.state.saveUserSettingsForm.default_sort_type ?? 0
]
}
onChange={this.handleSortTypeChange}
className="form-check-input"
id="user-show-nsfw"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.show_nsfw
- )}
+ checked={this.state.saveUserSettingsForm.show_nsfw}
onChange={linkEvent(this, this.handleShowNsfwChange)}
/>
<label className="form-check-label" htmlFor="user-show-nsfw">
className="form-check-input"
id="user-show-scores"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.show_scores
- )}
+ checked={this.state.saveUserSettingsForm.show_scores}
onChange={linkEvent(this, this.handleShowScoresChange)}
/>
<label className="form-check-label" htmlFor="user-show-scores">
className="form-check-input"
id="user-show-avatars"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.show_avatars
- )}
+ checked={this.state.saveUserSettingsForm.show_avatars}
onChange={linkEvent(this, this.handleShowAvatarsChange)}
/>
<label className="form-check-label" htmlFor="user-show-avatars">
className="form-check-input"
id="user-bot-account"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.bot_account
- )}
+ checked={this.state.saveUserSettingsForm.bot_account}
onChange={linkEvent(this, this.handleBotAccount)}
/>
<label className="form-check-label" htmlFor="user-bot-account">
className="form-check-input"
id="user-show-bot-accounts"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.show_bot_accounts
- )}
+ checked={this.state.saveUserSettingsForm.show_bot_accounts}
onChange={linkEvent(this, this.handleShowBotAccounts)}
/>
<label
className="form-check-input"
id="user-show-read-posts"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.show_read_posts
- )}
+ checked={this.state.saveUserSettingsForm.show_read_posts}
onChange={linkEvent(this, this.handleReadPosts)}
/>
<label
className="form-check-input"
id="user-show-new-post-notifs"
type="checkbox"
- checked={toUndefined(
- this.state.saveUserSettingsForm.show_new_post_notifs
- )}
+ checked={this.state.saveUserSettingsForm.show_new_post_notifs}
onChange={linkEvent(this, this.handleShowNewPostNotifs)}
/>
<label
id="user-send-notifications-to-email"
type="checkbox"
disabled={!this.state.saveUserSettingsForm.email}
- checked={toUndefined(
+ checked={
this.state.saveUserSettingsForm.send_notifications_to_email
- )}
+ }
onChange={linkEvent(
this,
this.handleSendNotificationsToEmailChange
}
handleBlockPerson(personId: number) {
- if (personId != 0) {
- let blockUserForm = new BlockPerson({
+ let auth = myAuth();
+ if (auth && personId != 0) {
+ let blockUserForm: BlockPerson = {
person_id: personId,
block: true,
- auth: auth().unwrap(),
- });
+ auth,
+ };
WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
}
}
handleUnblockPerson(i: { ctx: Settings; recipientId: number }) {
- let blockUserForm = new BlockPerson({
- person_id: i.recipientId,
- block: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockUserForm: BlockPerson = {
+ person_id: i.recipientId,
+ block: false,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
}
handleBlockCommunity(community_id: number) {
- if (community_id != 0) {
- let blockCommunityForm = new BlockCommunity({
+ let auth = myAuth();
+ if (auth && community_id != 0) {
+ let blockCommunityForm: BlockCommunity = {
community_id,
block: true,
- auth: auth().unwrap(),
- });
+ auth,
+ };
WebSocketService.Instance.send(
wsClient.blockCommunity(blockCommunityForm)
);
}
handleUnblockCommunity(i: { ctx: Settings; communityId: number }) {
- let blockCommunityForm = new BlockCommunity({
- community_id: i.communityId,
- block: false,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockCommunityForm: BlockCommunity = {
+ community_id: i.communityId,
+ block: false,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.blockCommunity(blockCommunityForm)
+ );
+ }
}
handleShowNsfwChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.show_nsfw = Some(event.target.checked);
+ i.state.saveUserSettingsForm.show_nsfw = event.target.checked;
i.setState(i.state);
}
handleShowAvatarsChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.show_avatars = Some(event.target.checked);
- UserService.Instance.myUserInfo.match({
- some: mui =>
- (mui.local_user_view.local_user.show_avatars = event.target.checked),
- none: void 0,
- });
+ i.state.saveUserSettingsForm.show_avatars = event.target.checked;
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ mui.local_user_view.local_user.show_avatars = event.target.checked;
+ }
i.setState(i.state);
}
handleBotAccount(i: Settings, event: any) {
- i.state.saveUserSettingsForm.bot_account = Some(event.target.checked);
+ i.state.saveUserSettingsForm.bot_account = event.target.checked;
i.setState(i.state);
}
handleShowBotAccounts(i: Settings, event: any) {
- i.state.saveUserSettingsForm.show_bot_accounts = Some(event.target.checked);
+ i.state.saveUserSettingsForm.show_bot_accounts = event.target.checked;
i.setState(i.state);
}
handleReadPosts(i: Settings, event: any) {
- i.state.saveUserSettingsForm.show_read_posts = Some(event.target.checked);
+ i.state.saveUserSettingsForm.show_read_posts = event.target.checked;
i.setState(i.state);
}
handleShowNewPostNotifs(i: Settings, event: any) {
- i.state.saveUserSettingsForm.show_new_post_notifs = Some(
- event.target.checked
- );
+ i.state.saveUserSettingsForm.show_new_post_notifs = event.target.checked;
i.setState(i.state);
}
handleShowScoresChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.show_scores = Some(event.target.checked);
- UserService.Instance.myUserInfo.match({
- some: mui =>
- (mui.local_user_view.local_user.show_scores = event.target.checked),
- none: void 0,
- });
+ i.state.saveUserSettingsForm.show_scores = event.target.checked;
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ mui.local_user_view.local_user.show_scores = event.target.checked;
+ }
i.setState(i.state);
}
handleSendNotificationsToEmailChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.send_notifications_to_email = Some(
- event.target.checked
- );
+ i.state.saveUserSettingsForm.send_notifications_to_email =
+ event.target.checked;
i.setState(i.state);
}
handleThemeChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.theme = Some(event.target.value);
+ i.state.saveUserSettingsForm.theme = event.target.value;
setTheme(event.target.value, true);
i.setState(i.state);
}
handleInterfaceLangChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.interface_language = Some(event.target.value);
+ i.state.saveUserSettingsForm.interface_language = event.target.value;
i18n.changeLanguage(
- getLanguages(i.state.saveUserSettingsForm.interface_language.unwrap())[0]
+ getLanguages(i.state.saveUserSettingsForm.interface_language).at(0)
);
i.setState(i.state);
}
handleDiscussionLanguageChange(val: number[]) {
this.setState(
- s => ((s.saveUserSettingsForm.discussion_languages = Some(val)), s)
+ s => ((s.saveUserSettingsForm.discussion_languages = val), s)
);
}
handleSortTypeChange(val: SortType) {
this.setState(
s => (
- (s.saveUserSettingsForm.default_sort_type = Some(
- Object.keys(SortType).indexOf(val)
- )),
+ (s.saveUserSettingsForm.default_sort_type =
+ Object.keys(SortType).indexOf(val)),
s
)
);
handleListingTypeChange(val: ListingType) {
this.setState(
s => (
- (s.saveUserSettingsForm.default_listing_type = Some(
- Object.keys(ListingType).indexOf(val)
- )),
+ (s.saveUserSettingsForm.default_listing_type =
+ Object.keys(ListingType).indexOf(val)),
s
)
);
}
handleEmailChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.email = Some(event.target.value);
+ i.state.saveUserSettingsForm.email = event.target.value;
i.setState(i.state);
}
handleBioChange(val: string) {
- this.setState(s => ((s.saveUserSettingsForm.bio = Some(val)), s));
+ this.setState(s => ((s.saveUserSettingsForm.bio = val), s));
}
handleAvatarUpload(url: string) {
- this.setState(s => ((s.saveUserSettingsForm.avatar = Some(url)), s));
+ this.setState(s => ((s.saveUserSettingsForm.avatar = url), s));
}
handleAvatarRemove() {
- this.setState(s => ((s.saveUserSettingsForm.avatar = Some("")), s));
+ this.setState(s => ((s.saveUserSettingsForm.avatar = ""), s));
}
handleBannerUpload(url: string) {
- this.setState(s => ((s.saveUserSettingsForm.banner = Some(url)), s));
+ this.setState(s => ((s.saveUserSettingsForm.banner = url), s));
}
handleBannerRemove() {
- this.setState(s => ((s.saveUserSettingsForm.banner = Some("")), s));
+ this.setState(s => ((s.saveUserSettingsForm.banner = ""), s));
}
handleDisplayNameChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.display_name = Some(event.target.value);
+ i.state.saveUserSettingsForm.display_name = event.target.value;
i.setState(i.state);
}
handleMatrixUserIdChange(i: Settings, event: any) {
- i.state.saveUserSettingsForm.matrix_user_id = Some(event.target.value);
+ i.state.saveUserSettingsForm.matrix_user_id = event.target.value;
i.setState(i.state);
}
handleSaveSettingsSubmit(i: Settings, event: any) {
event.preventDefault();
i.setState({ saveUserSettingsLoading: true });
- i.setState(s => ((s.saveUserSettingsForm.auth = auth().unwrap()), s));
-
- let form = new SaveUserSettings({ ...i.state.saveUserSettingsForm });
- WebSocketService.Instance.send(wsClient.saveUserSettings(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: SaveUserSettings = { ...i.state.saveUserSettingsForm, auth };
+ WebSocketService.Instance.send(wsClient.saveUserSettings(form));
+ }
}
handleChangePasswordSubmit(i: Settings, event: any) {
event.preventDefault();
i.setState({ changePasswordLoading: true });
- i.setState(s => ((s.changePasswordForm.auth = auth().unwrap()), s));
-
- let form = new ChangePassword({ ...i.state.changePasswordForm });
+ let auth = myAuth();
+ let pForm = i.state.changePasswordForm;
+ let new_password = pForm.new_password;
+ let new_password_verify = pForm.new_password_verify;
+ let old_password = pForm.old_password;
+ if (auth && new_password && old_password && new_password_verify) {
+ let form: ChangePassword = {
+ new_password,
+ new_password_verify,
+ old_password,
+ auth,
+ };
- WebSocketService.Instance.send(wsClient.changePassword(form));
+ WebSocketService.Instance.send(wsClient.changePassword(form));
+ }
}
handleDeleteAccountShowConfirmToggle(i: Settings, event: any) {
handleDeleteAccount(i: Settings, event: any) {
event.preventDefault();
i.setState({ deleteAccountLoading: true });
- i.setState(s => ((s.deleteAccountForm.auth = auth().unwrap()), s));
-
- let form = new DeleteAccount({ ...i.state.deleteAccountForm });
-
- WebSocketService.Instance.send(wsClient.deleteAccount(form));
+ let auth = myAuth();
+ let password = i.state.deleteAccountForm.password;
+ if (auth && password) {
+ let form: DeleteAccount = {
+ password,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.deleteAccount(form));
+ }
}
handleSwitchTab(i: { ctx: Settings; tab: string }) {
toast(i18n.t(msg.error), "danger");
return;
} else if (op == UserOperation.SaveUserSettings) {
- let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
+ let data = wsJsonToRes<LoginResponse>(msg);
UserService.Instance.login(data);
location.reload();
this.setState({ saveUserSettingsLoading: false });
toast(i18n.t("saved"));
window.scrollTo(0, 0);
} else if (op == UserOperation.ChangePassword) {
- let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
+ let data = wsJsonToRes<LoginResponse>(msg);
UserService.Instance.login(data);
this.setState({ changePasswordLoading: false });
window.scrollTo(0, 0);
UserService.Instance.logout();
window.location.href = "/";
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
- updatePersonBlock(data).match({
- some: blocks => this.setState({ personBlocks: blocks }),
- none: void 0,
- });
+ let data = wsJsonToRes<BlockPersonResponse>(msg);
+ updatePersonBlock(data);
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ this.setState({ personBlocks: mui.person_blocks });
+ }
} else if (op == UserOperation.BlockCommunity) {
- let data = wsJsonToRes<BlockCommunityResponse>(
- msg,
- BlockCommunityResponse
- );
- updateCommunityBlock(data).match({
- some: blocks => this.setState({ communityBlocks: blocks }),
- none: void 0,
- });
+ let data = wsJsonToRes<BlockCommunityResponse>(msg);
+ updateCommunityBlock(data);
+ let mui = UserService.Instance.myUserInfo;
+ if (mui) {
+ this.setState({ communityBlocks: mui.community_blocks });
+ }
}
}
}
-import { None } from "@sniptt/monads/build";
import { Component } from "inferno";
import {
GetSiteResponse,
export class VerifyEmail extends Component<any, State> {
private isoData = setIsoData(this.context);
- private subscription: Subscription;
+ private subscription?: Subscription;
- emptyState: State = {
- verifyEmailForm: new VerifyEmailForm({
+ state: State = {
+ verifyEmailForm: {
token: this.props.match.params.token,
- }),
+ },
siteRes: this.isoData.site_res,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<div className="row">
<div className="col-12 col-lg-6 offset-lg-3 mb-4">
this.props.history.push("/");
return;
} else if (op == UserOperation.VerifyEmail) {
- let data = wsJsonToRes<VerifyEmailResponse>(msg, VerifyEmailResponse);
+ let data = wsJsonToRes<VerifyEmailResponse>(msg);
if (data) {
toast(i18n.t("email_verified"));
- this.setState(this.emptyState);
this.props.history.push("/login");
}
}
-import { Either, Left, None, Option, Right, Some } from "@sniptt/monads";
import { Component } from "inferno";
import {
GetCommunity,
ListingType,
PostView,
SortType,
- toOption,
UserOperation,
wsJsonToRes,
wsUserOp,
import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
enableDownvotes,
enableNsfw,
fetchLimit,
isBrowser,
+ myAuth,
setIsoData,
toast,
wsClient,
import { PostForm } from "./post-form";
interface CreatePostState {
- listCommunitiesResponse: Option<ListCommunitiesResponse>;
+ listCommunitiesResponse?: ListCommunitiesResponse;
siteRes: GetSiteResponse;
loading: boolean;
}
export class CreatePost extends Component<any, CreatePostState> {
- private isoData = setIsoData(this.context, ListCommunitiesResponse);
- private subscription: Subscription;
- private emptyState: CreatePostState = {
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: CreatePostState = {
siteRes: this.isoData.site_res,
- listCommunitiesResponse: None,
loading: true,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePostCreate = this.handlePostCreate.bind(this);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
- if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+ if (!UserService.Instance.myUserInfo && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`);
}
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- listCommunitiesResponse: Some(
- this.isoData.routeData[0] as ListCommunitiesResponse
- ),
+ listCommunitiesResponse: this.isoData
+ .routeData[0] as ListCommunitiesResponse,
loading: false,
};
} else {
}
refetch() {
- this.params.nameOrId.match({
- some: opt =>
- opt.match({
- left: name => {
- let form = new GetCommunity({
- name: Some(name),
- id: None,
- auth: auth(false).ok(),
- });
- WebSocketService.Instance.send(wsClient.getCommunity(form));
- },
- right: id => {
- let form = new GetCommunity({
- id: Some(id),
- name: None,
- auth: auth(false).ok(),
- });
- WebSocketService.Instance.send(wsClient.getCommunity(form));
- },
- }),
- none: () => {
- let listCommunitiesForm = new ListCommunities({
- type_: Some(ListingType.All),
- sort: Some(SortType.TopAll),
- limit: Some(fetchLimit),
- page: None,
- auth: auth(false).ok(),
- });
- WebSocketService.Instance.send(
- wsClient.listCommunities(listCommunitiesForm)
- );
- },
- });
+ let nameOrId = this.params.nameOrId;
+ let auth = myAuth(false);
+ if (nameOrId) {
+ if (typeof nameOrId === "string") {
+ let form: GetCommunity = {
+ name: nameOrId,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.getCommunity(form));
+ } else {
+ let form: GetCommunity = {
+ id: nameOrId,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.getCommunity(form));
+ }
+ } else {
+ let listCommunitiesForm: ListCommunities = {
+ type_: ListingType.All,
+ sort: SortType.TopAll,
+ limit: fetchLimit,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.listCommunities(listCommunitiesForm)
+ );
+ }
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
}
render() {
+ let res = this.state.listCommunitiesResponse;
return (
<div className="container-lg">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
{this.state.loading ? (
<h5>
<Spinner large />
</h5>
) : (
- this.state.listCommunitiesResponse.match({
- some: res => (
- <div className="row">
- <div className="col-12 col-lg-6 offset-lg-3 mb-4">
- <h5>{i18n.t("create_post")}</h5>
- <PostForm
- post_view={None}
- communities={Some(res.communities)}
- onCreate={this.handlePostCreate}
- params={Some(this.params)}
- enableDownvotes={enableDownvotes(this.state.siteRes)}
- enableNsfw={enableNsfw(this.state.siteRes)}
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={this.state.siteRes.discussion_languages}
- />
- </div>
+ res && (
+ <div className="row">
+ <div className="col-12 col-lg-6 offset-lg-3 mb-4">
+ <h5>{i18n.t("create_post")}</h5>
+ <PostForm
+ communities={res.communities}
+ onCreate={this.handlePostCreate}
+ params={this.params}
+ enableDownvotes={enableDownvotes(this.state.siteRes)}
+ enableNsfw={enableNsfw(this.state.siteRes)}
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ />
</div>
- ),
- none: <></>,
- })
+ </div>
+ )
)}
</div>
);
get params(): PostFormParams {
let urlParams = new URLSearchParams(this.props.location.search);
- let name = toOption(urlParams.get("community_name")).or(
- this.prevCommunityName
- );
- let id = toOption(urlParams.get("community_id"))
- .map(Number)
- .or(this.prevCommunityId);
- let nameOrId: Option<Either<string, number>>;
- if (name.isSome()) {
- nameOrId = Some(Left(name.unwrap()));
- } else if (id.isSome()) {
- nameOrId = Some(Right(id.unwrap()));
- } else {
- nameOrId = None;
+ let name = urlParams.get("community_name") ?? this.prevCommunityName;
+ let communityIdParam = urlParams.get("community_id");
+ let id = communityIdParam ? Number(communityIdParam) : this.prevCommunityId;
+ let nameOrId: string | number | undefined;
+ if (name) {
+ nameOrId = name;
+ } else if (id) {
+ nameOrId = id;
}
let params: PostFormParams = {
- name: toOption(urlParams.get("title")),
+ name: urlParams.get("title") ?? undefined,
nameOrId,
- body: toOption(urlParams.get("body")),
- url: toOption(urlParams.get("url")),
+ body: urlParams.get("body") ?? undefined,
+ url: urlParams.get("url") ?? undefined,
};
return params;
}
- get prevCommunityName(): Option<string> {
+ get prevCommunityName(): string | undefined {
if (this.props.match.params.name) {
- return toOption(this.props.match.params.name);
+ return this.props.match.params.name;
} else if (this.props.location.state) {
let lastLocation = this.props.location.state.prevPath;
if (lastLocation.includes("/c/")) {
- return toOption(lastLocation.split("/c/")[1]);
+ return lastLocation.split("/c/").at(1);
}
}
- return None;
+ return undefined;
}
- get prevCommunityId(): Option<number> {
- if (this.props.match.params.id) {
- return toOption(this.props.match.params.id);
- }
- return None;
+ get prevCommunityId(): number | undefined {
+ // TODO is this actually a number? Whats the real return type
+ let id = this.props.match.params.id;
+ return id ?? undefined;
}
handlePostCreate(post_view: PostView) {
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
- let listCommunitiesForm = new ListCommunities({
- type_: Some(ListingType.All),
- sort: Some(SortType.TopAll),
- limit: Some(fetchLimit),
- page: None,
+ let listCommunitiesForm: ListCommunities = {
+ type_: ListingType.All,
+ sort: SortType.TopAll,
+ limit: fetchLimit,
auth: req.auth,
- });
+ };
return [req.client.listCommunities(listCommunitiesForm)];
}
toast(i18n.t(msg.error), "danger");
return;
} else if (op == UserOperation.ListCommunities) {
- let data = wsJsonToRes<ListCommunitiesResponse>(
- msg,
- ListCommunitiesResponse
- );
- this.setState({ listCommunitiesResponse: Some(data), loading: false });
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg);
+ this.setState({ listCommunitiesResponse: data, loading: false });
} else if (op == UserOperation.GetCommunity) {
- let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
+ let data = wsJsonToRes<GetCommunityResponse>(msg);
this.setState({
- listCommunitiesResponse: Some({
+ listCommunitiesResponse: {
communities: [data.community_view],
- }),
+ },
loading: false,
});
}
MetadataCardProps,
MetadataCardState
> {
- private emptyState: MetadataCardState = {
+ state: MetadataCardState = {
expanded: false,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
}
render() {
let post = this.props.post;
return (
<>
- {!this.state.expanded &&
- post.embed_title.match({
- some: embedTitle =>
- post.url.match({
- some: url => (
- <div className="card border-secondary mt-3 mb-2">
- <div className="row">
- <div className="col-12">
- <div className="card-body">
- {post.name !== embedTitle && (
- <>
- <h5 className="card-title d-inline">
- <a
- className="text-body"
- href={url}
- rel={relTags}
- >
- {embedTitle}
- </a>
- </h5>
- <span className="d-inline-block ml-2 mb-2 small text-muted">
- <a
- className="text-muted font-italic"
- href={url}
- rel={relTags}
- >
- {new URL(url).hostname}
- <Icon icon="external-link" classes="ml-1" />
- </a>
- </span>
- </>
- )}
- {post.embed_description.match({
- some: desc => (
- <div
- className="card-text small text-muted md-div"
- dangerouslySetInnerHTML={{
- __html: sanitizeHtml(desc),
- }}
- />
- ),
- none: <></>,
- })}
- {post.embed_video_url.isSome() && (
- <button
- className="mt-2 btn btn-secondary text-monospace"
- onClick={linkEvent(this, this.handleIframeExpand)}
- >
- {i18n.t("expand_here")}
- </button>
- )}
- </div>
- </div>
- </div>
- </div>
- ),
- none: <></>,
- }),
- none: <></>,
- })}
- {this.state.expanded &&
- post.embed_video_url.match({
- some: video_url => <iframe src={video_url}></iframe>,
- none: <></>,
- })}
+ {!this.state.expanded && post.embed_title && post.url && (
+ <div className="card border-secondary mt-3 mb-2">
+ <div className="row">
+ <div className="col-12">
+ <div className="card-body">
+ {post.name !== post.embed_title && (
+ <>
+ <h5 className="card-title d-inline">
+ <a className="text-body" href={post.url} rel={relTags}>
+ {post.embed_title}
+ </a>
+ </h5>
+ <span className="d-inline-block ml-2 mb-2 small text-muted">
+ <a
+ className="text-muted font-italic"
+ href={post.url}
+ rel={relTags}
+ >
+ {new URL(post.url).hostname}
+ <Icon icon="external-link" classes="ml-1" />
+ </a>
+ </span>
+ </>
+ )}
+ {post.embed_description && (
+ <div
+ className="card-text small text-muted md-div"
+ dangerouslySetInnerHTML={{
+ __html: sanitizeHtml(post.embed_description),
+ }}
+ />
+ )}
+ {post.embed_video_url && (
+ <button
+ className="mt-2 btn btn-secondary text-monospace"
+ onClick={linkEvent(this, this.handleIframeExpand)}
+ >
+ {i18n.t("expand_here")}
+ </button>
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+ )}
+ {this.state.expanded && post.embed_video_url && (
+ <iframe src={post.embed_video_url}></iframe>
+ )}
</>
);
}
-import { None, Option, Some } from "@sniptt/monads";
import autosize from "autosize";
import { Component, linkEvent } from "inferno";
import { Prompt } from "inferno-router";
SearchResponse,
SearchType,
SortType,
- toUndefined,
UserOperation,
wsJsonToRes,
wsUserOp,
import { UserService, WebSocketService } from "../../services";
import {
archiveTodayUrl,
- auth,
capitalizeFirstLetter,
choicesConfig,
communitySelectName,
ghostArchiveUrl,
isBrowser,
isImage,
+ myAuth,
myFirstDiscussionLanguageId,
pictrsDeleteToast,
relTags,
const MAX_POST_TITLE_LENGTH = 200;
interface PostFormProps {
- post_view: Option<PostView>; // If a post is given, that means this is an edit
+ post_view?: PostView; // If a post is given, that means this is an edit
allLanguages: Language[];
siteLanguages: number[];
- communities: Option<CommunityView[]>;
- params: Option<PostFormParams>;
+ communities?: CommunityView[];
+ params?: PostFormParams;
onCancel?(): any;
onCreate?(post: PostView): any;
onEdit?(post: PostView): any;
}
interface PostFormState {
- postForm: CreatePost;
- suggestedTitle: Option<string>;
- suggestedPosts: Option<PostView[]>;
- crossPosts: Option<PostView[]>;
+ form: {
+ name?: string;
+ url?: string;
+ body?: string;
+ nsfw?: boolean;
+ language_id?: number;
+ community_id?: number;
+ honeypot?: string;
+ };
+ suggestedTitle?: string;
+ suggestedPosts?: PostView[];
+ crossPosts?: PostView[];
loading: boolean;
imageLoading: boolean;
communitySearchLoading: boolean;
}
export class PostForm extends Component<PostFormProps, PostFormState> {
- private subscription: Subscription;
+ private subscription?: Subscription;
private choices: any;
- private emptyState: PostFormState = {
- postForm: new CreatePost({
- community_id: undefined,
- name: undefined,
- nsfw: Some(false),
- url: None,
- body: None,
- honeypot: None,
- language_id: None,
- auth: undefined,
- }),
+ state: PostFormState = {
+ form: {},
loading: false,
imageLoading: false,
communitySearchLoading: false,
previewMode: false,
- suggestedTitle: None,
- suggestedPosts: None,
- crossPosts: None,
};
constructor(props: any, context: any) {
this.handlePostBodyChange = this.handlePostBodyChange.bind(this);
this.handleLanguageChange = this.handleLanguageChange.bind(this);
- this.state = this.emptyState;
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
// Means its an edit
- if (this.props.post_view.isSome()) {
- let pv = this.props.post_view.unwrap();
-
+ let pv = this.props.post_view;
+ if (pv) {
this.state = {
...this.state,
- postForm: new CreatePost({
+ form: {
body: pv.post.body,
name: pv.post.name,
community_id: pv.community.id,
url: pv.post.url,
- nsfw: Some(pv.post.nsfw),
- honeypot: None,
- language_id: Some(pv.post.language_id),
- auth: auth().unwrap(),
- }),
+ nsfw: pv.post.nsfw,
+ language_id: pv.post.language_id,
+ },
};
}
- if (this.props.params.isSome()) {
- let params = this.props.params.unwrap();
+ let params = this.props.params;
+ if (params) {
this.state = {
...this.state,
- postForm: {
- ...this.state.postForm,
- name: toUndefined(params.name),
+ form: {
+ ...this.state.form,
+ name: params.name,
url: params.url,
body: params.body,
},
componentDidUpdate() {
if (
!this.state.loading &&
- (this.state.postForm.name ||
- this.state.postForm.url.isSome() ||
- this.state.postForm.body.isSome())
+ (this.state.form.name || this.state.form.url || this.state.form.body)
) {
window.onbeforeunload = () => true;
} else {
- window.onbeforeunload = undefined;
+ window.onbeforeunload = null;
}
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
/* this.choices && this.choices.destroy(); */
window.onbeforeunload = null;
}
render() {
- let selectedLangs = this.state.postForm.language_id
- .or(
- myFirstDiscussionLanguageId(
- this.props.allLanguages,
- this.props.siteLanguages,
- UserService.Instance.myUserInfo
- )
- )
- .map(Array.of);
+ let firstLang =
+ this.state.form.language_id ??
+ myFirstDiscussionLanguageId(
+ this.props.allLanguages,
+ this.props.siteLanguages,
+ UserService.Instance.myUserInfo
+ );
+ let selectedLangs = firstLang ? Array.of(firstLang) : undefined;
+ let url = this.state.form.url;
return (
<div>
<Prompt
when={
!this.state.loading &&
- (this.state.postForm.name ||
- this.state.postForm.url.isSome() ||
- this.state.postForm.body.isSome())
+ (this.state.form.name ||
+ this.state.form.url ||
+ this.state.form.body)
}
message={i18n.t("block_leaving")}
/>
type="url"
id="post-url"
className="form-control"
- value={toUndefined(this.state.postForm.url)}
+ value={this.state.form.url}
onInput={linkEvent(this, this.handlePostUrlChange)}
onPaste={linkEvent(this, this.handleImageUploadPaste)}
/>
- {this.state.suggestedTitle.match({
- some: title => (
- <div
- className="mt-1 text-muted small font-weight-bold pointer"
- role="button"
- onClick={linkEvent(this, this.copySuggestedTitle)}
- >
- {i18n.t("copy_suggested_title", { title: "" })} {title}
- </div>
- ),
- none: <></>,
- })}
+ {this.state.suggestedTitle && (
+ <div
+ className="mt-1 text-muted small font-weight-bold pointer"
+ role="button"
+ onClick={linkEvent(this, this.copySuggestedTitle)}
+ >
+ {i18n.t("copy_suggested_title", { title: "" })}{" "}
+ {this.state.suggestedTitle}
+ </div>
+ )}
<form>
<label
htmlFor="file-upload"
className={`${
- UserService.Instance.myUserInfo.isSome() && "pointer"
+ UserService.Instance.myUserInfo && "pointer"
} d-inline-block float-right text-muted font-weight-bold`}
data-tippy-content={i18n.t("upload_image")}
>
accept="image/*,video/*"
name="file"
className="d-none"
- disabled={UserService.Instance.myUserInfo.isNone()}
+ disabled={!UserService.Instance.myUserInfo}
onChange={linkEvent(this, this.handleImageUpload)}
/>
</form>
- {this.state.postForm.url.match({
- some: url =>
- validURL(url) && (
- <div>
- <a
- href={`${webArchiveUrl}/save/${encodeURIComponent(
- url
- )}`}
- className="mr-2 d-inline-block float-right text-muted small font-weight-bold"
- rel={relTags}
- >
- archive.org {i18n.t("archive_link")}
- </a>
- <a
- href={`${ghostArchiveUrl}/search?term=${encodeURIComponent(
- url
- )}`}
- className="mr-2 d-inline-block float-right text-muted small font-weight-bold"
- rel={relTags}
- >
- ghostarchive.org {i18n.t("archive_link")}
- </a>
- <a
- href={`${archiveTodayUrl}/?run=1&url=${encodeURIComponent(
- url
- )}`}
- className="mr-2 d-inline-block float-right text-muted small font-weight-bold"
- rel={relTags}
- >
- archive.today {i18n.t("archive_link")}
- </a>
- </div>
- ),
- none: <></>,
- })}
+ {url && validURL(url) && (
+ <div>
+ <a
+ href={`${webArchiveUrl}/save/${encodeURIComponent(url)}`}
+ className="mr-2 d-inline-block float-right text-muted small font-weight-bold"
+ rel={relTags}
+ >
+ archive.org {i18n.t("archive_link")}
+ </a>
+ <a
+ href={`${ghostArchiveUrl}/search?term=${encodeURIComponent(
+ url
+ )}`}
+ className="mr-2 d-inline-block float-right text-muted small font-weight-bold"
+ rel={relTags}
+ >
+ ghostarchive.org {i18n.t("archive_link")}
+ </a>
+ <a
+ href={`${archiveTodayUrl}/?run=1&url=${encodeURIComponent(
+ url
+ )}`}
+ className="mr-2 d-inline-block float-right text-muted small font-weight-bold"
+ rel={relTags}
+ >
+ archive.today {i18n.t("archive_link")}
+ </a>
+ </div>
+ )}
{this.state.imageLoading && <Spinner />}
- {this.state.postForm.url.match({
- some: url =>
- isImage(url) && (
- <img src={url} className="img-fluid" alt="" />
- ),
- none: <></>,
- })}
- {this.state.crossPosts.match({
- some: xPosts =>
- xPosts.length > 0 && (
- <>
- <div className="my-1 text-muted small font-weight-bold">
- {i18n.t("cross_posts")}
- </div>
- <PostListings
- showCommunity
- posts={xPosts}
- enableDownvotes={this.props.enableDownvotes}
- enableNsfw={this.props.enableNsfw}
- allLanguages={this.props.allLanguages}
- siteLanguages={this.props.siteLanguages}
- />
- </>
- ),
- none: <></>,
- })}
+ {url && isImage(url) && (
+ <img src={url} className="img-fluid" alt="" />
+ )}
+ {this.state.crossPosts && this.state.crossPosts.length > 0 && (
+ <>
+ <div className="my-1 text-muted small font-weight-bold">
+ {i18n.t("cross_posts")}
+ </div>
+ <PostListings
+ showCommunity
+ posts={this.state.crossPosts}
+ enableDownvotes={this.props.enableDownvotes}
+ enableNsfw={this.props.enableNsfw}
+ allLanguages={this.props.allLanguages}
+ siteLanguages={this.props.siteLanguages}
+ />
+ </>
+ )}
</div>
</div>
<div className="form-group row">
</label>
<div className="col-sm-10">
<textarea
- value={this.state.postForm.name}
+ value={this.state.form.name}
id="post-title"
onInput={linkEvent(this, this.handlePostNameChange)}
className={`form-control ${
- !validTitle(this.state.postForm.name) && "is-invalid"
+ !validTitle(this.state.form.name) && "is-invalid"
}`}
required
rows={1}
minLength={3}
maxLength={MAX_POST_TITLE_LENGTH}
/>
- {!validTitle(this.state.postForm.name) && (
+ {!validTitle(this.state.form.name) && (
<div className="invalid-feedback">
{i18n.t("invalid_post_title")}
</div>
)}
- {this.state.suggestedPosts.match({
- some: sPosts =>
- sPosts.length > 0 && (
- <>
- <div className="my-1 text-muted small font-weight-bold">
- {i18n.t("related_posts")}
- </div>
- <PostListings
- showCommunity
- posts={sPosts}
- enableDownvotes={this.props.enableDownvotes}
- enableNsfw={this.props.enableNsfw}
- allLanguages={this.props.allLanguages}
- siteLanguages={this.props.siteLanguages}
- />
- </>
- ),
- none: <></>,
- })}
+ {this.state.suggestedPosts &&
+ this.state.suggestedPosts.length > 0 && (
+ <>
+ <div className="my-1 text-muted small font-weight-bold">
+ {i18n.t("related_posts")}
+ </div>
+ <PostListings
+ showCommunity
+ posts={this.state.suggestedPosts}
+ enableDownvotes={this.props.enableDownvotes}
+ enableNsfw={this.props.enableNsfw}
+ allLanguages={this.props.allLanguages}
+ siteLanguages={this.props.siteLanguages}
+ />
+ </>
+ )}
</div>
</div>
<label className="col-sm-2 col-form-label">{i18n.t("body")}</label>
<div className="col-sm-10">
<MarkdownTextArea
- initialContent={this.state.postForm.body}
- initialLanguageId={None}
+ initialContent={this.state.form.body}
onContentChange={this.handlePostBodyChange}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
allLanguages={this.props.allLanguages}
siteLanguages={this.props.siteLanguages}
/>
</div>
</div>
- {this.props.post_view.isNone() && (
+ {!this.props.post_view && (
<div className="form-group row">
<label
className="col-sm-2 col-form-label"
<select
className="form-control"
id="post-community"
- value={this.state.postForm.community_id}
+ value={this.state.form.community_id}
onInput={linkEvent(this, this.handlePostCommunityChange)}
>
<option>{i18n.t("select_a_community")}</option>
- {this.props.communities.unwrapOr([]).map(cv => (
+ {this.props.communities?.map(cv => (
<option key={cv.community.id} value={cv.community.id}>
{communitySelectName(cv)}
</option>
className="form-check-input position-static"
id="post-nsfw"
type="checkbox"
- checked={toUndefined(this.state.postForm.nsfw)}
+ checked={this.state.form.nsfw}
onChange={linkEvent(this, this.handlePostNsfwChange)}
/>
</div>
type="text"
className="form-control honeypot"
id="register-honey"
- value={toUndefined(this.state.postForm.honeypot)}
+ value={this.state.form.honeypot}
onInput={linkEvent(this, this.handleHoneyPotChange)}
/>
<div className="form-group row">
<div className="col-sm-10">
<button
- disabled={
- !this.state.postForm.community_id || this.state.loading
- }
+ disabled={!this.state.form.community_id || this.state.loading}
type="submit"
className="btn btn-secondary mr-2"
>
{this.state.loading ? (
<Spinner />
- ) : this.props.post_view.isSome() ? (
+ ) : this.props.post_view ? (
capitalizeFirstLetter(i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("create"))
)}
</button>
- {this.props.post_view.isSome() && (
+ {this.props.post_view && (
<button
type="button"
className="btn btn-secondary"
i.setState({ loading: true });
// Coerce empty url string to undefined
- if (
- i.state.postForm.url.isSome() &&
- i.state.postForm.url.unwrapOr("blank") === ""
- ) {
- i.setState(s => ((s.postForm.url = None), s));
+ if ((i.state.form.url ?? "blank") === "") {
+ i.setState(s => ((s.form.url = undefined), s));
}
- let pForm = i.state.postForm;
- i.props.post_view.match({
- some: pv => {
- let form = new EditPost({
- name: Some(pForm.name),
+ let pForm = i.state.form;
+ let pv = i.props.post_view;
+ let auth = myAuth();
+ if (auth) {
+ if (pv) {
+ let form: EditPost = {
+ name: pForm.name,
url: pForm.url,
body: pForm.body,
nsfw: pForm.nsfw,
post_id: pv.post.id,
- language_id: Some(pv.post.language_id),
- auth: auth().unwrap(),
- });
+ language_id: pv.post.language_id,
+ auth,
+ };
WebSocketService.Instance.send(wsClient.editPost(form));
- },
- none: () => {
- i.setState(s => ((s.postForm.auth = auth().unwrap()), s));
- let form = new CreatePost({ ...i.state.postForm });
- WebSocketService.Instance.send(wsClient.createPost(form));
- },
- });
+ } else {
+ if (pForm.name && pForm.community_id) {
+ let form: CreatePost = {
+ name: pForm.name,
+ community_id: pForm.community_id,
+ url: pForm.url,
+ body: pForm.body,
+ nsfw: pForm.nsfw,
+ language_id: pForm.language_id,
+ honeypot: pForm.honeypot,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.createPost(form));
+ }
+ }
+ }
}
copySuggestedTitle(i: PostForm) {
- i.state.suggestedTitle.match({
- some: sTitle => {
- i.setState(
- s => (
- (s.postForm.name = sTitle.substring(0, MAX_POST_TITLE_LENGTH)), s
- )
- );
- i.setState({ suggestedTitle: None });
- setTimeout(() => {
- let textarea: any = document.getElementById("post-title");
- autosize.update(textarea);
- }, 10);
- },
- none: void 0,
- });
+ let sTitle = i.state.suggestedTitle;
+ if (sTitle) {
+ i.setState(
+ s => ((s.form.name = sTitle?.substring(0, MAX_POST_TITLE_LENGTH)), s)
+ );
+ i.setState({ suggestedTitle: undefined });
+ setTimeout(() => {
+ let textarea: any = document.getElementById("post-title");
+ autosize.update(textarea);
+ }, 10);
+ }
}
handlePostUrlChange(i: PostForm, event: any) {
- i.setState(s => ((s.postForm.url = Some(event.target.value)), s));
+ i.setState(s => ((s.form.url = event.target.value), s));
i.fetchPageTitle();
}
fetchPageTitle() {
- this.state.postForm.url.match({
- some: url => {
- if (validURL(url)) {
- let form = new Search({
- q: url,
- community_id: None,
- community_name: None,
- creator_id: None,
- type_: Some(SearchType.Url),
- sort: Some(SortType.TopAll),
- listing_type: Some(ListingType.All),
- page: Some(1),
- limit: Some(trendingFetchLimit),
- auth: auth(false).ok(),
- });
-
- WebSocketService.Instance.send(wsClient.search(form));
-
- // Fetch the page title
- getSiteMetadata(url).then(d => {
- this.setState({ suggestedTitle: d.metadata.title });
- });
- } else {
- this.setState({ suggestedTitle: None, crossPosts: None });
- }
- },
- none: void 0,
- });
+ let url = this.state.form.url;
+ if (url && validURL(url)) {
+ let form: Search = {
+ q: url,
+ type_: SearchType.Url,
+ sort: SortType.TopAll,
+ listing_type: ListingType.All,
+ page: 1,
+ limit: trendingFetchLimit,
+ auth: myAuth(false),
+ };
+
+ WebSocketService.Instance.send(wsClient.search(form));
+
+ // Fetch the page title
+ getSiteMetadata(url).then(d => {
+ this.setState({ suggestedTitle: d.metadata.title });
+ });
+ } else {
+ this.setState({ suggestedTitle: undefined, crossPosts: undefined });
+ }
}
handlePostNameChange(i: PostForm, event: any) {
- i.setState(s => ((s.postForm.name = event.target.value), s));
+ i.setState(s => ((s.form.name = event.target.value), s));
i.fetchSimilarPosts();
}
fetchSimilarPosts() {
- let form = new Search({
- q: this.state.postForm.name,
- type_: Some(SearchType.Posts),
- sort: Some(SortType.TopAll),
- listing_type: Some(ListingType.All),
- community_id: Some(this.state.postForm.community_id),
- community_name: None,
- creator_id: None,
- page: Some(1),
- limit: Some(trendingFetchLimit),
- auth: auth(false).ok(),
- });
-
- if (this.state.postForm.name !== "") {
+ let q = this.state.form.name;
+ if (q && q !== "") {
+ let form: Search = {
+ q,
+ type_: SearchType.Posts,
+ sort: SortType.TopAll,
+ listing_type: ListingType.All,
+ community_id: this.state.form.community_id,
+ page: 1,
+ limit: trendingFetchLimit,
+ auth: myAuth(false),
+ };
+
WebSocketService.Instance.send(wsClient.search(form));
} else {
- this.setState({ suggestedPosts: None });
+ this.setState({ suggestedPosts: undefined });
}
}
handlePostBodyChange(val: string) {
- this.setState(s => ((s.postForm.body = Some(val)), s));
+ this.setState(s => ((s.form.body = val), s));
}
handlePostCommunityChange(i: PostForm, event: any) {
- i.setState(
- s => ((s.postForm.community_id = Number(event.target.value)), s)
- );
+ i.setState(s => ((s.form.community_id = Number(event.target.value)), s));
}
handlePostNsfwChange(i: PostForm, event: any) {
- i.setState(s => ((s.postForm.nsfw = Some(event.target.checked)), s));
+ i.setState(s => ((s.form.nsfw = event.target.checked), s));
}
handleLanguageChange(val: number[]) {
- this.setState(s => ((s.postForm.language_id = Some(val[0])), s));
+ this.setState(s => ((s.form.language_id = val.at(0)), s));
}
handleHoneyPotChange(i: PostForm, event: any) {
- i.setState(s => ((s.postForm.honeypot = Some(event.target.value)), s));
+ i.setState(s => ((s.form.honeypot = event.target.value), s));
}
handleCancel(i: PostForm) {
- i.props.onCancel();
+ i.props.onCancel?.();
}
handlePreviewToggle(i: PostForm, event: any) {
let url = `${pictrsUri}/${hash}`;
let deleteToken = res.files[0].delete_token;
let deleteUrl = `${pictrsUri}/delete/${deleteToken}/${hash}`;
- i.state.postForm.url = Some(url);
+ i.state.form.url = url;
i.setState({ imageLoading: false });
pictrsDeleteToast(
`${i18n.t("click_to_delete_picture")}: ${file.name}`,
"choice",
(e: any) => {
this.setState(
- s => (
- (s.postForm.community_id = Number(e.detail.choice.value)), s
- )
+ s => ((s.form.community_id = Number(e.detail.choice.value)), s)
);
},
false
}
}
- this.props.post_view.match({
- some: pv =>
- this.setState(s => ((s.postForm.community_id = pv.community.id), s)),
- none: void 0,
- });
- this.props.params.match({
- some: params =>
- params.nameOrId.match({
- some: nameOrId =>
- nameOrId.match({
- left: name => {
- let foundCommunityId = this.props.communities
- .unwrapOr([])
- .find(r => r.community.name == name).community.id;
- this.setState(
- s => ((s.postForm.community_id = foundCommunityId), s)
- );
- },
- right: id =>
- this.setState(s => ((s.postForm.community_id = id), s)),
- }),
- none: void 0,
- }),
- none: void 0,
- });
-
- if (isBrowser() && this.state.postForm.community_id) {
- this.choices.setChoiceByValue(
- this.state.postForm.community_id.toString()
- );
+ let pv = this.props.post_view;
+ this.setState(s => ((s.form.community_id = pv?.community.id), s));
+
+ let nameOrId = this.props.params?.nameOrId;
+ if (nameOrId) {
+ if (typeof nameOrId === "string") {
+ let name_ = nameOrId;
+ let foundCommunityId = this.props.communities?.find(
+ r => r.community.name == name_
+ )?.community.id;
+ this.setState(s => ((s.form.community_id = foundCommunityId), s));
+ } else {
+ let id = nameOrId;
+ this.setState(s => ((s.form.community_id = id), s));
+ }
+ }
+
+ if (isBrowser() && this.state.form.community_id) {
+ this.choices.setChoiceByValue(this.state.form.community_id.toString());
}
this.setState(this.state);
}
parseMessage(msg: any) {
+ let mui = UserService.Instance.myUserInfo;
let op = wsUserOp(msg);
console.log(msg);
if (msg.error) {
this.setState({ loading: false });
return;
} else if (op == UserOperation.CreatePost) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- UserService.Instance.myUserInfo.match({
- some: mui => {
- if (data.post_view.creator.id == mui.local_user_view.person.id) {
- this.props.onCreate(data.post_view);
- }
- },
- none: void 0,
- });
+ let data = wsJsonToRes<PostResponse>(msg);
+ if (data.post_view.creator.id == mui?.local_user_view.person.id) {
+ this.props.onCreate?.(data.post_view);
+ }
} else if (op == UserOperation.EditPost) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- UserService.Instance.myUserInfo.match({
- some: mui => {
- if (data.post_view.creator.id == mui.local_user_view.person.id) {
- this.setState({ loading: false });
- this.props.onEdit(data.post_view);
- }
- },
- none: void 0,
- });
+ let data = wsJsonToRes<PostResponse>(msg);
+ if (data.post_view.creator.id == mui?.local_user_view.person.id) {
+ this.setState({ loading: false });
+ this.props.onEdit?.(data.post_view);
+ }
} else if (op == UserOperation.Search) {
- let data = wsJsonToRes<SearchResponse>(msg, SearchResponse);
+ let data = wsJsonToRes<SearchResponse>(msg);
if (data.type_ == SearchType[SearchType.Posts]) {
- this.setState({ suggestedPosts: Some(data.posts) });
+ this.setState({ suggestedPosts: data.posts });
} else if (data.type_ == SearchType[SearchType.Url]) {
- this.setState({ crossPosts: Some(data.posts) });
+ this.setState({ crossPosts: data.posts });
}
}
}
-import { None, Option, Some } from "@sniptt/monads";
import classNames from "classnames";
import { Component, linkEvent } from "inferno";
import { Link } from "inferno-router";
PurgePost,
RemovePost,
SavePost,
- toUndefined,
TransferCommunity,
} from "lemmy-js-client";
import { externalHost } from "../../env";
import {
amAdmin,
amCommunityCreator,
- auth,
canAdmin,
canMod,
futureDaysToUnixTime,
mdNoImages,
mdToHtml,
mdToHtmlInline,
+ myAuth,
numToSI,
relTags,
setupTippy,
showEdit: boolean;
showRemoveDialog: boolean;
showPurgeDialog: boolean;
- purgeReason: Option<string>;
- purgeType: PurgeType;
+ purgeReason?: string;
+ purgeType?: PurgeType;
purgeLoading: boolean;
- removeReason: Option<string>;
+ removeReason?: string;
showBanDialog: boolean;
- banReason: Option<string>;
- banExpireDays: Option<number>;
- banType: BanType;
- removeData: boolean;
+ banReason?: string;
+ banExpireDays?: number;
+ banType?: BanType;
+ removeData?: boolean;
showConfirmTransferSite: boolean;
showConfirmTransferCommunity: boolean;
imageExpanded: boolean;
showMoreMobile: boolean;
showBody: boolean;
showReportDialog: boolean;
- reportReason: Option<string>;
- my_vote: Option<number>;
+ reportReason?: string;
+ my_vote?: number;
score: number;
upvotes: number;
downvotes: number;
interface PostListingProps {
post_view: PostView;
- duplicates: Option<PostView[]>;
- moderators: Option<CommunityModeratorView[]>;
- admins: Option<PersonViewSafe[]>;
+ duplicates?: PostView[];
+ moderators?: CommunityModeratorView[];
+ admins?: PersonViewSafe[];
allLanguages: Language[];
siteLanguages: number[];
showCommunity?: boolean;
}
export class PostListing extends Component<PostListingProps, PostListingState> {
- private emptyState: PostListingState = {
+ state: PostListingState = {
showEdit: false,
showRemoveDialog: false,
showPurgeDialog: false,
- purgeReason: None,
purgeType: PurgeType.Person,
purgeLoading: false,
- removeReason: None,
showBanDialog: false,
- banReason: None,
- banExpireDays: None,
banType: BanType.Community,
removeData: false,
showConfirmTransferSite: false,
showMoreMobile: false,
showBody: false,
showReportDialog: false,
- reportReason: None,
my_vote: this.props.post_view.my_vote,
score: this.props.post_view.counts.score,
upvotes: this.props.post_view.counts.upvotes,
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePostLike = this.handlePostLike.bind(this);
this.handlePostDisLike = this.handlePostDisLike.bind(this);
this.handleEditPost = this.handleEditPost.bind(this);
<>
{this.listing()}
{this.state.imageExpanded && !this.props.hideImage && this.img}
- {post.url.isSome() &&
- this.showBody &&
- post.embed_title.isSome() && <MetadataCard post={post} />}
+ {post.url && this.showBody && post.embed_title && (
+ <MetadataCard post={post} />
+ )}
{this.showBody && this.body()}
</>
) : (
<div className="col-12">
<PostForm
- post_view={Some(this.props.post_view)}
- communities={None}
- params={None}
+ post_view={this.props.post_view}
onEdit={this.handleEditPost}
onCancel={this.handleEditCancel}
enableNsfw={this.props.enableNsfw}
}
body() {
- return this.props.post_view.post.body.match({
- some: body => (
- <div className="col-12 card my-2 p-2">
- {this.state.viewSource ? (
- <pre>{body}</pre>
- ) : (
- <div className="md-div" dangerouslySetInnerHTML={mdToHtml(body)} />
- )}
- </div>
- ),
- none: <></>,
- });
+ let body = this.props.post_view.post.body;
+ return body ? (
+ <div className="col-12 card my-2 p-2">
+ {this.state.viewSource ? (
+ <pre>{body}</pre>
+ ) : (
+ <div className="md-div" dangerouslySetInnerHTML={mdToHtml(body)} />
+ )}
+ </div>
+ ) : (
+ <></>
+ );
}
get img() {
- return this.imageSrc.match({
- some: src => (
- <>
- <div className="offset-sm-3 my-2 d-none d-sm-block">
- <a href={src} className="d-inline-block">
- <PictrsImage src={src} />
- </a>
- </div>
- <div className="my-2 d-block d-sm-none">
- <a
- className="d-inline-block"
- onClick={linkEvent(this, this.handleImageExpandClick)}
- >
- <PictrsImage src={src} />
- </a>
- </div>
- </>
- ),
- none: <></>,
- });
+ let src = this.imageSrc;
+ return src ? (
+ <>
+ <div className="offset-sm-3 my-2 d-none d-sm-block">
+ <a href={src} className="d-inline-block">
+ <PictrsImage src={src} />
+ </a>
+ </div>
+ <div className="my-2 d-block d-sm-none">
+ <a
+ className="d-inline-block"
+ onClick={linkEvent(this, this.handleImageExpandClick)}
+ >
+ <PictrsImage src={src} />
+ </a>
+ </div>
+ </>
+ ) : (
+ <></>
+ );
}
imgThumb(src: string) {
);
}
- get imageSrc(): Option<string> {
+ get imageSrc(): string | undefined {
let post = this.props.post_view.post;
let url = post.url;
let thumbnail = post.thumbnail_url;
- if (url.isSome() && isImage(url.unwrap())) {
- if (url.unwrap().includes("pictrs")) {
+ if (url && isImage(url)) {
+ if (url.includes("pictrs")) {
return url;
- } else if (thumbnail.isSome()) {
+ } else if (thumbnail) {
return thumbnail;
} else {
return url;
}
- } else if (thumbnail.isSome()) {
+ } else if (thumbnail) {
return thumbnail;
} else {
- return None;
+ return undefined;
}
}
let url = post.url;
let thumbnail = post.thumbnail_url;
- if (!this.props.hideImage && url.isSome() && isImage(url.unwrap())) {
+ if (!this.props.hideImage && url && isImage(url) && this.imageSrc) {
return (
<a
- href={this.imageSrc.unwrap()}
+ href={this.imageSrc}
className="text-body d-inline-block position-relative mb-2"
data-tippy-content={i18n.t("expand_here")}
onClick={linkEvent(this, this.handleImageExpandClick)}
aria-label={i18n.t("expand_here")}
>
- {this.imgThumb(this.imageSrc.unwrap())}
+ {this.imgThumb(this.imageSrc)}
<Icon icon="image" classes="mini-overlay" />
</a>
);
- } else if (!this.props.hideImage && url.isSome() && thumbnail.isSome()) {
+ } else if (!this.props.hideImage && url && thumbnail && this.imageSrc) {
return (
<a
className="text-body d-inline-block position-relative mb-2"
- href={url.unwrap()}
+ href={url}
rel={relTags}
- title={url.unwrap()}
+ title={url}
>
- {this.imgThumb(this.imageSrc.unwrap())}
+ {this.imgThumb(this.imageSrc)}
<Icon icon="external-link" classes="mini-overlay" />
</a>
);
- } else if (url.isSome()) {
- if (!this.props.hideImage && isVideo(url.unwrap())) {
+ } else if (url) {
+ if (!this.props.hideImage && isVideo(url)) {
return (
<div className="embed-responsive embed-responsive-16by9">
<video
controls
className="embed-responsive-item"
>
- <source src={url.unwrap()} type="video/mp4" />
+ <source src={url} type="video/mp4" />
</video>
</div>
);
} else {
return (
- <a
- className="text-body"
- href={url.unwrap()}
- title={url.unwrap()}
- rel={relTags}
- >
+ <a className="text-body" href={url} title={url} rel={relTags}>
<div className="thumbnail rounded bg-light d-flex justify-content-center">
<Icon icon="external-link" classes="d-flex align-items-center" />
</div>
createdLine() {
let post_view = this.props.post_view;
+ let url = post_view.post.url;
+ let body = post_view.post.body;
return (
<ul className="list-inline mb-1 text-muted small">
<li className="list-inline-item">
)}
</li>
<li className="list-inline-item">•</li>
- {post_view.post.url.match({
- some: url =>
- !(hostname(url) == externalHost) && (
- <>
- <li className="list-inline-item">
- <a
- className="text-muted font-italic"
- href={url}
- title={url}
- rel={relTags}
- >
- {hostname(url)}
- </a>
- </li>
- <li className="list-inline-item">•</li>
- </>
- ),
- none: <></>,
- })}
+ {url && !(hostname(url) == externalHost) && (
+ <>
+ <li className="list-inline-item">
+ <a
+ className="text-muted font-italic"
+ href={url}
+ title={url}
+ rel={relTags}
+ >
+ {hostname(url)}
+ </a>
+ </li>
+ <li className="list-inline-item">•</li>
+ </>
+ )}
<li className="list-inline-item">
<span>
<MomentTime
/>
</span>
</li>
- {post_view.post.body.match({
- some: body => (
- <>
- <li className="list-inline-item">•</li>
- <li className="list-inline-item">
- <button
- className="text-muted btn btn-sm btn-link p-0"
- data-tippy-content={mdNoImages.render(body)}
- data-tippy-allowHtml={true}
- onClick={linkEvent(this, this.handleShowBody)}
- >
- <Icon icon="book-open" classes="icon-inline mr-1" />
- </button>
- </li>
- </>
- ),
- none: <></>,
- })}
+ {body && (
+ <>
+ <li className="list-inline-item">•</li>
+ <li className="list-inline-item">
+ <button
+ className="text-muted btn btn-sm btn-link p-0"
+ data-tippy-content={mdNoImages.render(body)}
+ data-tippy-allowHtml={true}
+ onClick={linkEvent(this, this.handleShowBody)}
+ >
+ <Icon icon="book-open" classes="icon-inline mr-1" />
+ </button>
+ </li>
+ </>
+ )}
</ul>
);
}
<div className={`vote-bar col-1 pr-0 small text-center`}>
<button
className={`btn-animate btn btn-link p-0 ${
- this.state.my_vote.unwrapOr(0) == 1 ? "text-info" : "text-muted"
+ this.state.my_vote == 1 ? "text-info" : "text-muted"
}`}
onClick={this.handlePostLike}
data-tippy-content={i18n.t("upvote")}
{this.props.enableDownvotes && (
<button
className={`btn-animate btn btn-link p-0 ${
- this.state.my_vote.unwrapOr(0) == -1
- ? "text-danger"
- : "text-muted"
+ this.state.my_vote == -1 ? "text-danger" : "text-muted"
}`}
onClick={this.handlePostDisLike}
data-tippy-content={i18n.t("downvote")}
postTitleLine() {
let post = this.props.post_view.post;
+ let url = post.url;
+
return (
<div className="post-title overflow-hidden">
<h5>
- {post.url.match({
- some: url =>
- this.props.showBody ? (
- <a
- className={
- !post.featured_community && !post.featured_local
- ? "text-body"
- : "text-primary"
- }
- href={url}
- title={url}
- rel={relTags}
- >
- <div dangerouslySetInnerHTML={mdToHtmlInline(post.name)} />
- </a>
- ) : (
- this.postLink
- ),
- none: this.postLink,
- })}
- {post.url.map(isImage).or(post.thumbnail_url).unwrapOr(false) && (
- <button
- className="btn btn-link text-monospace text-muted small d-inline-block ml-2"
- data-tippy-content={i18n.t("expand_here")}
- onClick={linkEvent(this, this.handleImageExpandClick)}
- >
- <Icon
- icon={
- !this.state.imageExpanded ? "plus-square" : "minus-square"
+ {url ? (
+ this.props.showBody ? (
+ <a
+ className={
+ !post.featured_community && !post.featured_local
+ ? "text-body"
+ : "text-primary"
}
- classes="icon-inline"
- />
- </button>
+ href={url}
+ title={url}
+ rel={relTags}
+ >
+ <div dangerouslySetInnerHTML={mdToHtmlInline(post.name)} />
+ </a>
+ ) : (
+ this.postLink
+ )
+ ) : (
+ this.postLink
)}
+ {(url && isImage(url)) ||
+ (post.thumbnail_url && (
+ <button
+ className="btn btn-link text-monospace text-muted small d-inline-block ml-2"
+ data-tippy-content={i18n.t("expand_here")}
+ onClick={linkEvent(this, this.handleImageExpandClick)}
+ >
+ <Icon
+ icon={
+ !this.state.imageExpanded ? "plus-square" : "minus-square"
+ }
+ classes="icon-inline"
+ />
+ </button>
+ ))}
{post.removed && (
<small className="ml-2 text-muted font-italic">
{i18n.t("removed")}
}
duplicatesLine() {
- return this.props.duplicates.match({
- some: dupes =>
- dupes.length > 0 && (
- <ul className="list-inline mb-1 small text-muted">
- <>
- <li className="list-inline-item mr-2">
- {i18n.t("cross_posted_to")}
- </li>
- {dupes.map(pv => (
- <li key={pv.post.id} className="list-inline-item mr-2">
- <Link to={`/post/${pv.post.id}`}>
- {pv.community.local
- ? pv.community.name
- : `${pv.community.name}@${hostname(
- pv.community.actor_id
- )}`}
- </Link>
- </li>
- ))}
- </>
- </ul>
- ),
- none: <></>,
- });
+ let dupes = this.props.duplicates;
+ return dupes && dupes.length > 0 ? (
+ <ul className="list-inline mb-1 small text-muted">
+ <>
+ <li className="list-inline-item mr-2">{i18n.t("cross_posted_to")}</li>
+ {dupes.map(pv => (
+ <li key={pv.post.id} className="list-inline-item mr-2">
+ <Link to={`/post/${pv.post.id}`}>
+ {pv.community.local
+ ? pv.community.name
+ : `${pv.community.name}@${hostname(pv.community.actor_id)}`}
+ </Link>
+ </li>
+ ))}
+ </>
+ </ul>
+ ) : (
+ <></>
+ );
}
commentsLine(mobile = false) {
</a>
)}
{mobile && !this.props.viewOnly && this.mobileVotes}
- {UserService.Instance.myUserInfo.isSome() &&
+ {UserService.Instance.myUserInfo &&
!this.props.viewOnly &&
this.postActions(mobile)}
</div>
)}
{this.state.showAdvanced && (
<>
- {this.showBody &&
- post_view.post.body.isSome() &&
- this.viewSourceButton}
+ {this.showBody && post_view.post.body && this.viewSourceButton}
{this.canModOnSelf_ && (
<>
{this.lockButton}
formattedCount: numToSI(post_view.counts.comments),
})}
</span>
- {this.unreadCount.match({
- some: unreadCount => (
- <span className="small text-warning">
- ({unreadCount} {i18n.t("new")})
- </span>
- ),
- none: <></>,
- })}
+ {this.unreadCount && (
+ <span className="small text-warning">
+ ({this.unreadCount} {i18n.t("new")})
+ </span>
+ )}
</Link>
</button>
);
}
- get unreadCount(): Option<number> {
+ get unreadCount(): number | undefined {
let pv = this.props.post_view;
- if (pv.unread_comments == pv.counts.comments || pv.unread_comments == 0) {
- return None;
- } else {
- return Some(pv.unread_comments);
- }
+ return pv.unread_comments == pv.counts.comments || pv.unread_comments == 0
+ ? undefined
+ : pv.unread_comments;
}
get mobileVotes() {
<div>
<button
className={`btn-animate btn py-0 px-1 ${
- this.state.my_vote.unwrapOr(0) == 1 ? "text-info" : "text-muted"
+ this.state.my_vote == 1 ? "text-info" : "text-muted"
}`}
{...tippy}
onClick={this.handlePostLike}
{this.props.enableDownvotes && (
<button
className={`ml-2 btn-animate btn py-0 px-1 ${
- this.state.my_vote.unwrapOr(0) == -1
- ? "text-danger"
- : "text-muted"
+ this.state.my_vote == -1 ? "text-danger" : "text-muted"
}`}
onClick={this.handlePostDisLike}
{...tippy}
</>
)}
{/* Community creators and admins can transfer community to another mod */}
- {(amCommunityCreator(this.props.moderators, post_view.creator.id) ||
+ {(amCommunityCreator(post_view.creator.id, this.props.moderators) ||
this.canAdmin_) &&
this.creatorIsMod_ &&
(!this.state.showConfirmTransferCommunity ? (
removeAndBanDialogs() {
let post = this.props.post_view;
- let purgeTypeText: string;
- if (this.state.purgeType == PurgeType.Post) {
- purgeTypeText = i18n.t("purge_post");
- } else if (this.state.purgeType == PurgeType.Person) {
- purgeTypeText = `${i18n.t("purge")} ${post.creator.name}`;
- }
+ let purgeTypeText =
+ this.state.purgeType == PurgeType.Post
+ ? i18n.t("purge_post")
+ : `${i18n.t("purge")} ${post.creator.name}`;
return (
<>
{this.state.showRemoveDialog && (
id="post-listing-remove-reason"
className="form-control mr-2"
placeholder={i18n.t("reason")}
- value={toUndefined(this.state.removeReason)}
+ value={this.state.removeReason}
onInput={linkEvent(this, this.handleModRemoveReasonChange)}
/>
<button
id="post-listing-ban-reason"
className="form-control mr-2"
placeholder={i18n.t("reason")}
- value={toUndefined(this.state.banReason)}
+ value={this.state.banReason}
onInput={linkEvent(this, this.handleModBanReasonChange)}
/>
<label className="col-form-label" htmlFor={`mod-ban-expires`}>
id={`mod-ban-expires`}
className="form-control mr-2"
placeholder={i18n.t("number_of_days")}
- value={toUndefined(this.state.banExpireDays)}
+ value={this.state.banExpireDays}
onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
/>
<div className="form-group">
className="form-control mr-2"
placeholder={i18n.t("reason")}
required
- value={toUndefined(this.state.reportReason)}
+ value={this.state.reportReason}
onInput={linkEvent(this, this.handleReportReasonChange)}
/>
<button
id="purge-reason"
className="form-control mr-2"
placeholder={i18n.t("reason")}
- value={toUndefined(this.state.purgeReason)}
+ value={this.state.purgeReason}
onInput={linkEvent(this, this.handlePurgeReasonChange)}
/>
{this.state.purgeLoading ? (
mobileThumbnail() {
let post = this.props.post_view.post;
- return post.thumbnail_url.isSome() ||
- post.url.map(isImage).unwrapOr(false) ? (
+ return post.thumbnail_url || (post.url && isImage(post.url)) ? (
<div className="row">
<div className={`${this.state.imageExpanded ? "col-12" : "col-8"}`}>
{this.postTitleLine()}
}
showMobilePreview() {
- let post = this.props.post_view.post;
- return (
- !this.showBody &&
- post.body.match({
- some: body => <div className="md-div mb-1 preview-lines">{body}</div>,
- none: <></>,
- })
+ let body = this.props.post_view.post.body;
+ return !this.showBody && body ? (
+ <div className="md-div mb-1 preview-lines">{body}</div>
+ ) : (
+ <></>
);
}
}
private get myPost(): boolean {
- return UserService.Instance.myUserInfo.match({
- some: mui =>
- this.props.post_view.creator.id == mui.local_user_view.person.id,
- none: false,
- });
+ return (
+ this.props.post_view.creator.id ==
+ UserService.Instance.myUserInfo?.local_user_view.person.id
+ );
}
handlePostLike(event: any) {
event.preventDefault();
- if (UserService.Instance.myUserInfo.isNone()) {
+ if (!UserService.Instance.myUserInfo) {
this.context.router.history.push(`/login`);
}
- let myVote = this.state.my_vote.unwrapOr(0);
+ let myVote = this.state.my_vote;
let newVote = myVote == 1 ? 0 : 1;
if (myVote == 1) {
});
}
- this.setState({ my_vote: Some(newVote) });
+ this.setState({ my_vote: newVote });
- let form = new CreatePostLike({
- post_id: this.props.post_view.post.id,
- score: newVote,
- auth: auth().unwrap(),
- });
+ let auth = myAuth();
+ if (auth) {
+ let form: CreatePostLike = {
+ post_id: this.props.post_view.post.id,
+ score: newVote,
+ auth,
+ };
- WebSocketService.Instance.send(wsClient.likePost(form));
- this.setState(this.state);
+ WebSocketService.Instance.send(wsClient.likePost(form));
+ this.setState(this.state);
+ }
setupTippy();
}
handlePostDisLike(event: any) {
event.preventDefault();
- if (UserService.Instance.myUserInfo.isNone()) {
+ if (!UserService.Instance.myUserInfo) {
this.context.router.history.push(`/login`);
}
- let myVote = this.state.my_vote.unwrapOr(0);
+ let myVote = this.state.my_vote;
let newVote = myVote == -1 ? 0 : -1;
if (myVote == 1) {
});
}
- this.setState({ my_vote: Some(newVote) });
+ this.setState({ my_vote: newVote });
- let form = new CreatePostLike({
- post_id: this.props.post_view.post.id,
- score: newVote,
- auth: auth().unwrap(),
- });
+ let auth = myAuth();
+ if (auth) {
+ let form: CreatePostLike = {
+ post_id: this.props.post_view.post.id,
+ score: newVote,
+ auth,
+ };
- WebSocketService.Instance.send(wsClient.likePost(form));
- this.setState(this.state);
+ WebSocketService.Instance.send(wsClient.likePost(form));
+ this.setState(this.state);
+ }
setupTippy();
}
}
handleReportReasonChange(i: PostListing, event: any) {
- i.setState({ reportReason: Some(event.target.value) });
+ i.setState({ reportReason: event.target.value });
}
handleReportSubmit(i: PostListing, event: any) {
event.preventDefault();
- let form = new CreatePostReport({
- post_id: i.props.post_view.post.id,
- reason: toUndefined(i.state.reportReason),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.createPostReport(form));
+ let auth = myAuth();
+ let reason = i.state.reportReason;
+ if (auth && reason) {
+ let form: CreatePostReport = {
+ post_id: i.props.post_view.post.id,
+ reason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.createPostReport(form));
- i.setState({ showReportDialog: false });
+ i.setState({ showReportDialog: false });
+ }
}
handleBlockUserClick(i: PostListing) {
- let blockUserForm = new BlockPerson({
- person_id: i.props.post_view.creator.id,
- block: true,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ let auth = myAuth();
+ if (auth) {
+ let blockUserForm: BlockPerson = {
+ person_id: i.props.post_view.creator.id,
+ block: true,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+ }
}
handleDeleteClick(i: PostListing) {
- let deleteForm = new DeletePost({
- post_id: i.props.post_view.post.id,
- deleted: !i.props.post_view.post.deleted,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.deletePost(deleteForm));
+ let auth = myAuth();
+ if (auth) {
+ let deleteForm: DeletePost = {
+ post_id: i.props.post_view.post.id,
+ deleted: !i.props.post_view.post.deleted,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.deletePost(deleteForm));
+ }
}
handleSavePostClick(i: PostListing) {
- let saved =
- i.props.post_view.saved == undefined ? true : !i.props.post_view.saved;
- let form = new SavePost({
- post_id: i.props.post_view.post.id,
- save: saved,
- auth: auth().unwrap(),
- });
-
- WebSocketService.Instance.send(wsClient.savePost(form));
+ let auth = myAuth();
+ if (auth) {
+ let saved =
+ i.props.post_view.saved == undefined ? true : !i.props.post_view.saved;
+ let form: SavePost = {
+ post_id: i.props.post_view.post.id,
+ save: saved,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.savePost(form));
+ }
}
get crossPostParams(): string {
let post = this.props.post_view.post;
let params = `?title=${encodeURIComponent(post.name)}`;
- if (post.url.isSome()) {
- params += `&url=${encodeURIComponent(post.url.unwrap())}`;
+ if (post.url) {
+ params += `&url=${encodeURIComponent(post.url)}`;
}
- if (post.body.isSome()) {
- params += `&body=${encodeURIComponent(this.crossPostBody())}`;
+ let crossPostBody = this.crossPostBody();
+ if (crossPostBody) {
+ params += `&body=${encodeURIComponent(crossPostBody)}`;
}
return params;
}
- crossPostBody(): string {
+ crossPostBody(): string | undefined {
let post = this.props.post_view.post;
- let body = `${i18n.t("cross_posted_from")} ${post.ap_id}\n\n${post.body
- .unwrap()
- .replace(/^/gm, "> ")}`;
- return body;
+ let body = post.body;
+
+ return body
+ ? `${i18n.t("cross_posted_from")} ${post.ap_id}\n\n${body.replace(
+ /^/gm,
+ "> "
+ )}`
+ : undefined;
}
get showBody(): boolean {
}
handleModRemoveReasonChange(i: PostListing, event: any) {
- i.setState({ removeReason: Some(event.target.value) });
+ i.setState({ removeReason: event.target.value });
}
handleModRemoveDataChange(i: PostListing, event: any) {
handleModRemoveSubmit(i: PostListing, event: any) {
event.preventDefault();
- let form = new RemovePost({
- post_id: i.props.post_view.post.id,
- removed: !i.props.post_view.post.removed,
- reason: i.state.removeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.removePost(form));
- i.setState({ showRemoveDialog: false });
+ let auth = myAuth();
+ if (auth) {
+ let form: RemovePost = {
+ post_id: i.props.post_view.post.id,
+ removed: !i.props.post_view.post.removed,
+ reason: i.state.removeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.removePost(form));
+ i.setState({ showRemoveDialog: false });
+ }
}
handleModLock(i: PostListing) {
- let form = new LockPost({
- post_id: i.props.post_view.post.id,
- locked: !i.props.post_view.post.locked,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.lockPost(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: LockPost = {
+ post_id: i.props.post_view.post.id,
+ locked: !i.props.post_view.post.locked,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.lockPost(form));
+ }
}
handleModFeaturePost(i: PostListing, is_community: boolean) {
- let form = new FeaturePost({
- post_id: i.props.post_view.post.id,
- featured: is_community
- ? !i.props.post_view.post.featured_community
- : !i.props.post_view.post.featured_local,
- feature_type: is_community
- ? PostFeatureType.Community
- : PostFeatureType.Local,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.featurePost(form));
+ let auth = myAuth();
+ if (auth) {
+ let featured: [PostFeatureType, boolean] = is_community
+ ? [
+ PostFeatureType.Community,
+ !i.props.post_view.post.featured_community,
+ ]
+ : [PostFeatureType.Local, !i.props.post_view.post.featured_local];
+
+ let form: FeaturePost = {
+ post_id: i.props.post_view.post.id,
+ feature_type: featured[0],
+ featured: featured[1],
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.featurePost(form));
+ }
}
handleModBanFromCommunityShow(i: PostListing) {
}
handlePurgeReasonChange(i: PostListing, event: any) {
- i.setState({ purgeReason: Some(event.target.value) });
+ i.setState({ purgeReason: event.target.value });
}
handlePurgeSubmit(i: PostListing, event: any) {
event.preventDefault();
- if (i.state.purgeType == PurgeType.Person) {
- let form = new PurgePerson({
- person_id: i.props.post_view.creator.id,
- reason: i.state.purgeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.purgePerson(form));
- } else if (i.state.purgeType == PurgeType.Post) {
- let form = new PurgePost({
- post_id: i.props.post_view.post.id,
- reason: i.state.purgeReason,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.purgePost(form));
- }
+ let auth = myAuth();
+ if (auth) {
+ if (i.state.purgeType == PurgeType.Person) {
+ let form: PurgePerson = {
+ person_id: i.props.post_view.creator.id,
+ reason: i.state.purgeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.purgePerson(form));
+ } else if (i.state.purgeType == PurgeType.Post) {
+ let form: PurgePost = {
+ post_id: i.props.post_view.post.id,
+ reason: i.state.purgeReason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.purgePost(form));
+ }
- i.setState({ purgeLoading: true });
+ i.setState({ purgeLoading: true });
+ }
}
handleModBanReasonChange(i: PostListing, event: any) {
- i.setState({ banReason: Some(event.target.value) });
+ i.setState({ banReason: event.target.value });
}
handleModBanExpireDaysChange(i: PostListing, event: any) {
- i.setState({ banExpireDays: Some(event.target.value) });
+ i.setState({ banExpireDays: event.target.value });
}
handleModBanFromCommunitySubmit(i: PostListing) {
handleModBanBothSubmit(i: PostListing, event?: any) {
if (event) event.preventDefault();
-
- if (i.state.banType == BanType.Community) {
- // If its an unban, restore all their data
+ let auth = myAuth();
+ if (auth) {
let ban = !i.props.post_view.creator_banned_from_community;
- if (ban == false) {
- i.setState({ removeData: false });
- }
- let form = new BanFromCommunity({
- person_id: i.props.post_view.creator.id,
- community_id: i.props.post_view.community.id,
- ban,
- remove_data: Some(i.state.removeData),
- reason: i.state.banReason,
- expires: i.state.banExpireDays.map(futureDaysToUnixTime),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.banFromCommunity(form));
- } else {
- // If its an unban, restore all their data
- let ban = !i.props.post_view.creator.banned;
- if (ban == false) {
- i.setState({ removeData: false });
+ let person_id = i.props.post_view.creator.id;
+ let remove_data = i.state.removeData;
+ let reason = i.state.banReason;
+ let expires = futureDaysToUnixTime(i.state.banExpireDays);
+
+ if (i.state.banType == BanType.Community) {
+ // If its an unban, restore all their data
+ if (ban == false) {
+ i.setState({ removeData: false });
+ }
+
+ let form: BanFromCommunity = {
+ person_id,
+ community_id: i.props.post_view.community.id,
+ ban,
+ remove_data,
+ reason,
+ expires,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.banFromCommunity(form));
+ } else {
+ // If its an unban, restore all their data
+ let ban = !i.props.post_view.creator.banned;
+ if (ban == false) {
+ i.setState({ removeData: false });
+ }
+ let form: BanPerson = {
+ person_id,
+ ban,
+ remove_data,
+ reason,
+ expires,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.banPerson(form));
}
- let form = new BanPerson({
- person_id: i.props.post_view.creator.id,
- ban,
- remove_data: Some(i.state.removeData),
- reason: i.state.banReason,
- expires: i.state.banExpireDays.map(futureDaysToUnixTime),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.banPerson(form));
- }
- i.setState({ showBanDialog: false });
+ i.setState({ showBanDialog: false });
+ }
}
handleAddModToCommunity(i: PostListing) {
- let form = new AddModToCommunity({
- person_id: i.props.post_view.creator.id,
- community_id: i.props.post_view.community.id,
- added: !i.creatorIsMod_,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.addModToCommunity(form));
- i.setState(i.state);
+ let auth = myAuth();
+ if (auth) {
+ let form: AddModToCommunity = {
+ person_id: i.props.post_view.creator.id,
+ community_id: i.props.post_view.community.id,
+ added: !i.creatorIsMod_,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.addModToCommunity(form));
+ i.setState(i.state);
+ }
}
handleAddAdmin(i: PostListing) {
- let form = new AddAdmin({
- person_id: i.props.post_view.creator.id,
- added: !i.creatorIsAdmin_,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.addAdmin(form));
- i.setState(i.state);
+ let auth = myAuth();
+ if (auth) {
+ let form: AddAdmin = {
+ person_id: i.props.post_view.creator.id,
+ added: !i.creatorIsAdmin_,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.addAdmin(form));
+ i.setState(i.state);
+ }
}
handleShowConfirmTransferCommunity(i: PostListing) {
}
handleTransferCommunity(i: PostListing) {
- let form = new TransferCommunity({
- community_id: i.props.post_view.community.id,
- person_id: i.props.post_view.creator.id,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.transferCommunity(form));
- i.setState({ showConfirmTransferCommunity: false });
+ let auth = myAuth();
+ if (auth) {
+ let form: TransferCommunity = {
+ community_id: i.props.post_view.community.id,
+ person_id: i.props.post_view.creator.id,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.transferCommunity(form));
+ i.setState({ showConfirmTransferCommunity: false });
+ }
}
handleShowConfirmTransferSite(i: PostListing) {
get canModOnSelf_(): boolean {
return canMod(
+ this.props.post_view.creator.id,
this.props.moderators,
this.props.admins,
- this.props.post_view.creator.id,
undefined,
true
);
get canMod_(): boolean {
return canMod(
+ this.props.post_view.creator.id,
this.props.moderators,
- this.props.admins,
- this.props.post_view.creator.id
+ this.props.admins
);
}
get canAdmin_(): boolean {
- return canAdmin(this.props.admins, this.props.post_view.creator.id);
+ return canAdmin(this.props.post_view.creator.id, this.props.admins);
}
get creatorIsMod_(): boolean {
- return isMod(this.props.moderators, this.props.post_view.creator.id);
+ return isMod(this.props.post_view.creator.id, this.props.moderators);
}
get creatorIsAdmin_(): boolean {
- return isAdmin(this.props.admins, this.props.post_view.creator.id);
+ return isAdmin(this.props.post_view.creator.id, this.props.admins);
}
}
-import { None, Some } from "@sniptt/monads";
import { Component } from "inferno";
import { T } from "inferno-i18next-dess";
import { Link } from "inferno-router";
siteLanguages: number[];
showCommunity?: boolean;
removeDuplicates?: boolean;
- enableDownvotes: boolean;
- enableNsfw: boolean;
+ enableDownvotes?: boolean;
+ enableNsfw?: boolean;
}
export class PostListings extends Component<PostListingsProps, any> {
<>
<PostListing
post_view={post_view}
- duplicates={Some(this.duplicatesMap.get(post_view.post.id))}
- moderators={None}
- admins={None}
+ duplicates={this.duplicatesMap.get(post_view.post.id)}
showCommunity={this.props.showCommunity}
enableDownvotes={this.props.enableDownvotes}
enableNsfw={this.props.enableNsfw}
// Loop over the posts, find ones with same urls
for (let pv of posts) {
- !pv.post.deleted &&
+ let url = pv.post.url;
+ if (
+ !pv.post.deleted &&
!pv.post.removed &&
!pv.community.deleted &&
!pv.community.removed &&
- pv.post.url.match({
- some: url => {
- if (!urlMap.get(url)) {
- urlMap.set(url, [pv]);
- } else {
- urlMap.get(url).push(pv);
- }
- },
- none: void 0,
- });
+ url
+ ) {
+ if (!urlMap.get(url)) {
+ urlMap.set(url, [pv]);
+ } else {
+ urlMap.get(url)?.push(pv);
+ }
+ }
}
// Sort by oldest
for (let i = 0; i < posts.length; i++) {
let pv = posts[i];
- pv.post.url.match({
- some: url => {
- let found = urlMap.get(url);
- if (found) {
- // If its the oldest, add
- if (pv.post.id == found[0].post.id) {
- this.duplicatesMap.set(pv.post.id, found.slice(1));
- }
- // Otherwise, delete it
- else {
- posts.splice(i--, 1);
- }
+ let url = pv.post.url;
+ if (url) {
+ let found = urlMap.get(url);
+ if (found) {
+ // If its the oldest, add
+ if (pv.post.id == found[0].post.id) {
+ this.duplicatesMap.set(pv.post.id, found.slice(1));
+ }
+ // Otherwise, delete it
+ else {
+ posts.splice(i--, 1);
}
- },
- none: void 0,
- });
+ }
+ }
}
return posts;
-import { None } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import {
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
-import { auth, wsClient } from "../../utils";
+import { myAuth, wsClient } from "../../utils";
import { Icon } from "../common/icon";
import { PersonListing } from "../person/person-listing";
import { PostListing } from "./post-listing";
render() {
let r = this.props.report;
+ let resolver = r.resolver;
let post = r.post;
let tippyContent = i18n.t(
r.post_report.resolved ? "unresolve_report" : "resolve_report"
<div>
<PostListing
post_view={pv}
- duplicates={None}
- moderators={None}
- admins={None}
showCommunity={true}
enableDownvotes={true}
enableNsfw={true}
<div>
{i18n.t("reason")}: {r.post_report.reason}
</div>
- {r.resolver.match({
- some: resolver => (
- <div>
- {r.post_report.resolved ? (
- <T i18nKey="resolved_by">
- #
- <PersonListing person={resolver} />
- </T>
- ) : (
- <T i18nKey="unresolved_by">
- #
- <PersonListing person={resolver} />
- </T>
- )}
- </div>
- ),
- none: <></>,
- })}
+ {resolver && (
+ <div>
+ {r.post_report.resolved ? (
+ <T i18nKey="resolved_by">
+ #
+ <PersonListing person={resolver} />
+ </T>
+ ) : (
+ <T i18nKey="unresolved_by">
+ #
+ <PersonListing person={resolver} />
+ </T>
+ )}
+ </div>
+ )}
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleResolveReport)}
}
handleResolveReport(i: PostReport) {
- let form = new ResolvePostReport({
- report_id: i.props.report.post_report.id,
- resolved: !i.props.report.post_report.resolved,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.resolvePostReport(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: ResolvePostReport = {
+ report_id: i.props.report.post_report.id,
+ resolved: !i.props.report.post_report.resolved,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.resolvePostReport(form));
+ }
}
}
-import { None, Option, Right, Some } from "@sniptt/monads";
import autosize from "autosize";
import { Component, createRef, linkEvent, RefObject } from "inferno";
import {
SearchResponse,
SearchType,
SortType,
- toOption,
UserOperation,
wsJsonToRes,
wsUserOp,
import { CommentViewType, InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
buildCommentsTree,
commentsToFlatNodes,
commentTreeMaxDepth,
insertCommentIntoTree,
isBrowser,
isImage,
+ myAuth,
restoreScrollPosition,
saveCommentRes,
saveScrollPosition,
const commentsShownInterval = 15;
interface PostState {
- postId: Option<number>;
- commentId: Option<number>;
- postRes: Option<GetPostResponse>;
- commentsRes: Option<GetCommentsResponse>;
+ postId?: number;
+ commentId?: number;
+ postRes?: GetPostResponse;
+ commentsRes?: GetCommentsResponse;
commentTree: CommentNodeI[];
commentSort: CommentSortType;
commentViewType: CommentViewType;
scrolled?: boolean;
loading: boolean;
- crossPosts: Option<PostView[]>;
+ crossPosts?: PostView[];
siteRes: GetSiteResponse;
commentSectionRef?: RefObject<HTMLDivElement>;
showSidebarMobile: boolean;
}
export class Post extends Component<any, PostState> {
- private subscription: Subscription;
- private isoData = setIsoData(
- this.context,
- GetPostResponse,
- GetCommentsResponse
- );
+ private subscription?: Subscription;
+ private isoData = setIsoData(this.context);
private commentScrollDebounced: () => void;
- private emptyState: PostState = {
- postRes: None,
- commentsRes: None,
+ state: PostState = {
postId: getIdFromProps(this.props),
commentId: getCommentIdFromProps(this.props),
commentTree: [],
commentViewType: CommentViewType.Tree,
scrolled: false,
loading: true,
- crossPosts: None,
siteRes: this.isoData.site_res,
- commentSectionRef: null,
showSidebarMobile: false,
maxCommentsShown: commentsShownInterval,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- postRes: Some(this.isoData.routeData[0] as GetPostResponse),
- commentsRes: Some(this.isoData.routeData[1] as GetCommentsResponse),
+ postRes: this.isoData.routeData[0] as GetPostResponse,
+ commentsRes: this.isoData.routeData[1] as GetCommentsResponse,
};
- if (this.state.commentsRes.isSome()) {
+ if (this.state.commentsRes) {
this.state = {
...this.state,
commentTree: buildCommentsTree(
- this.state.commentsRes.unwrap().comments,
- this.state.commentId.isSome()
+ this.state.commentsRes.comments,
+ !!this.state.commentId
),
};
}
this.state = { ...this.state, loading: false };
if (isBrowser()) {
- WebSocketService.Instance.send(
- wsClient.communityJoin({
- community_id:
- this.state.postRes.unwrap().community_view.community.id,
- })
- );
+ if (this.state.postRes) {
+ WebSocketService.Instance.send(
+ wsClient.communityJoin({
+ community_id: this.state.postRes.community_view.community.id,
+ })
+ );
+ }
- this.state.postId.match({
- some: post_id =>
- WebSocketService.Instance.send(wsClient.postJoin({ post_id })),
- none: void 0,
- });
+ if (this.state.postId) {
+ WebSocketService.Instance.send(
+ wsClient.postJoin({ post_id: this.state.postId })
+ );
+ }
this.fetchCrossPosts();
}
fetchPost() {
- this.setState({ commentsRes: None });
- let postForm = new GetPost({
+ this.setState({ commentsRes: undefined, postRes: undefined });
+ let auth = myAuth(false);
+ let postForm: GetPost = {
id: this.state.postId,
comment_id: this.state.commentId,
- auth: auth(false).ok(),
- });
+ auth,
+ };
WebSocketService.Instance.send(wsClient.getPost(postForm));
- let commentsForm = new GetComments({
+ let commentsForm: GetComments = {
post_id: this.state.postId,
parent_id: this.state.commentId,
- max_depth: Some(commentTreeMaxDepth),
- page: None,
- limit: None,
- sort: Some(this.state.commentSort),
- type_: Some(ListingType.All),
- community_name: None,
- community_id: None,
- saved_only: Some(false),
- auth: auth(false).ok(),
- });
+ max_depth: commentTreeMaxDepth,
+ sort: this.state.commentSort,
+ type_: ListingType.All,
+ saved_only: false,
+ auth,
+ };
WebSocketService.Instance.send(wsClient.getComments(commentsForm));
}
fetchCrossPosts() {
- this.state.postRes
- .andThen(r => r.post_view.post.url)
- .match({
- some: url => {
- let form = new Search({
- q: url,
- type_: Some(SearchType.Url),
- sort: Some(SortType.TopAll),
- listing_type: Some(ListingType.All),
- page: Some(1),
- limit: Some(trendingFetchLimit),
- community_id: None,
- community_name: None,
- creator_id: None,
- auth: auth(false).ok(),
- });
- WebSocketService.Instance.send(wsClient.search(form));
- },
- none: void 0,
- });
+ let q = this.state.postRes?.post_view.post.url;
+ if (q) {
+ let form: Search = {
+ q,
+ type_: SearchType.Url,
+ sort: SortType.TopAll,
+ listing_type: ListingType.All,
+ page: 1,
+ limit: trendingFetchLimit,
+ auth: myAuth(false),
+ };
+ WebSocketService.Instance.send(wsClient.search(form));
+ }
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split("/");
let promises: Promise<any>[] = [];
- let pathType = pathSplit[1];
- let id = Number(pathSplit[2]);
+ let pathType = pathSplit.at(1);
+ let id = pathSplit.at(2) ? Number(pathSplit.at(2)) : undefined;
+ let auth = req.auth;
- let postForm = new GetPost({
- id: None,
- comment_id: None,
- auth: req.auth,
- });
+ let postForm: GetPost = {
+ auth,
+ };
- let commentsForm = new GetComments({
- post_id: None,
- parent_id: None,
- max_depth: Some(commentTreeMaxDepth),
- page: None,
- limit: None,
- sort: Some(CommentSortType.Hot),
- type_: Some(ListingType.All),
- community_name: None,
- community_id: None,
- saved_only: Some(false),
- auth: req.auth,
- });
+ let commentsForm: GetComments = {
+ max_depth: commentTreeMaxDepth,
+ sort: CommentSortType.Hot,
+ type_: ListingType.All,
+ saved_only: false,
+ auth,
+ };
// Set the correct id based on the path type
if (pathType == "post") {
- postForm.id = Some(id);
- commentsForm.post_id = Some(id);
+ postForm.id = id;
+ commentsForm.post_id = id;
} else {
- postForm.comment_id = Some(id);
- commentsForm.parent_id = Some(id);
+ postForm.comment_id = id;
+ commentsForm.parent_id = id;
}
promises.push(req.client.getPost(postForm));
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
document.removeEventListener("scroll", this.commentScrollDebounced);
saveScrollPosition(this.context);
}
scrollIntoCommentSection() {
- this.state.commentSectionRef.current?.scrollIntoView();
+ this.state.commentSectionRef?.current?.scrollIntoView();
}
isBottom(el: Element): boolean {
};
get documentTitle(): string {
- return this.state.postRes.match({
- some: res =>
- `${res.post_view.post.name} - ${this.state.siteRes.site_view.site.name}`,
- none: "",
- });
+ let name_ = this.state.postRes?.post_view.post.name;
+ let siteName = this.state.siteRes.site_view.site.name;
+ return name_ ? `${name_} - ${siteName}` : "";
}
- get imageTag(): Option<string> {
- return this.state.postRes.match({
- some: res =>
- res.post_view.post.thumbnail_url.or(
- res.post_view.post.url.match({
- some: url => (isImage(url) ? Some(url) : None),
- none: None,
- })
- ),
- none: None,
- });
- }
-
- get descriptionTag(): Option<string> {
- return this.state.postRes.andThen(r => r.post_view.post.body);
+ get imageTag(): string | undefined {
+ let post = this.state.postRes?.post_view.post;
+ let thumbnail = post?.thumbnail_url;
+ let url = post?.url;
+ return thumbnail || (url && isImage(url) ? url : undefined);
}
render() {
+ let res = this.state.postRes;
+ let description = res?.post_view.post.body;
return (
<div className="container-lg">
{this.state.loading ? (
<Spinner large />
</h5>
) : (
- this.state.postRes.match({
- some: res => (
- <div className="row">
- <div className="col-12 col-md-8 mb-3">
- <HtmlTags
- title={this.documentTitle}
- path={this.context.router.route.match.url}
- image={this.imageTag}
- description={this.descriptionTag}
- />
- <PostListing
- post_view={res.post_view}
- duplicates={this.state.crossPosts}
- showBody
- showCommunity
- moderators={Some(res.moderators)}
- admins={Some(this.state.siteRes.admins)}
- enableDownvotes={enableDownvotes(this.state.siteRes)}
- enableNsfw={enableNsfw(this.state.siteRes)}
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={this.state.siteRes.discussion_languages}
- />
- <div ref={this.state.commentSectionRef} className="mb-2" />
- <CommentForm
- node={Right(res.post_view.post.id)}
- disabled={res.post_view.post.locked}
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={this.state.siteRes.discussion_languages}
- />
- <div className="d-block d-md-none">
- <button
- className="btn btn-secondary d-inline-block mb-2 mr-3"
- onClick={linkEvent(this, this.handleShowSidebarMobile)}
- >
- {i18n.t("sidebar")}{" "}
- <Icon
- icon={
- this.state.showSidebarMobile
- ? `minus-square`
- : `plus-square`
- }
- classes="icon-inline"
- />
- </button>
- {this.state.showSidebarMobile && this.sidebar()}
- </div>
- {this.sortRadios()}
- {this.state.commentViewType == CommentViewType.Tree &&
- this.commentsTree()}
- {this.state.commentViewType == CommentViewType.Flat &&
- this.commentsFlat()}
- </div>
- <div className="d-none d-md-block col-md-4">
- {this.sidebar()}
+ res && (
+ <div className="row">
+ <div className="col-12 col-md-8 mb-3">
+ <HtmlTags
+ title={this.documentTitle}
+ path={this.context.router.route.match.url}
+ image={this.imageTag}
+ description={description}
+ />
+ <PostListing
+ post_view={res.post_view}
+ duplicates={this.state.crossPosts}
+ showBody
+ showCommunity
+ moderators={res.moderators}
+ admins={this.state.siteRes.admins}
+ enableDownvotes={enableDownvotes(this.state.siteRes)}
+ enableNsfw={enableNsfw(this.state.siteRes)}
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ />
+ <div ref={this.state.commentSectionRef} className="mb-2" />
+ <CommentForm
+ node={res.post_view.post.id}
+ disabled={res.post_view.post.locked}
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ />
+ <div className="d-block d-md-none">
+ <button
+ className="btn btn-secondary d-inline-block mb-2 mr-3"
+ onClick={linkEvent(this, this.handleShowSidebarMobile)}
+ >
+ {i18n.t("sidebar")}{" "}
+ <Icon
+ icon={
+ this.state.showSidebarMobile
+ ? `minus-square`
+ : `plus-square`
+ }
+ classes="icon-inline"
+ />
+ </button>
+ {this.state.showSidebarMobile && this.sidebar()}
</div>
+ {this.sortRadios()}
+ {this.state.commentViewType == CommentViewType.Tree &&
+ this.commentsTree()}
+ {this.state.commentViewType == CommentViewType.Flat &&
+ this.commentsFlat()}
</div>
- ),
- none: <></>,
- })
+ <div className="d-none d-md-block col-md-4">{this.sidebar()}</div>
+ </div>
+ )
)}
</div>
);
commentsFlat() {
// These are already sorted by new
- return this.state.commentsRes.match({
- some: commentsRes =>
- this.state.postRes.match({
- some: postRes => (
- <div>
- <CommentNodes
- nodes={commentsToFlatNodes(commentsRes.comments)}
- viewType={this.state.commentViewType}
- maxCommentsShown={Some(this.state.maxCommentsShown)}
- noIndent
- locked={postRes.post_view.post.locked}
- moderators={Some(postRes.moderators)}
- admins={Some(this.state.siteRes.admins)}
- enableDownvotes={enableDownvotes(this.state.siteRes)}
- showContext
- allLanguages={this.state.siteRes.all_languages}
- siteLanguages={this.state.siteRes.discussion_languages}
- />
- </div>
- ),
- none: <></>,
- }),
- none: <></>,
- });
+ let commentsRes = this.state.commentsRes;
+ let postRes = this.state.postRes;
+ return (
+ commentsRes &&
+ postRes && (
+ <div>
+ <CommentNodes
+ nodes={commentsToFlatNodes(commentsRes.comments)}
+ viewType={this.state.commentViewType}
+ maxCommentsShown={this.state.maxCommentsShown}
+ noIndent
+ locked={postRes.post_view.post.locked}
+ moderators={postRes.moderators}
+ admins={this.state.siteRes.admins}
+ enableDownvotes={enableDownvotes(this.state.siteRes)}
+ showContext
+ allLanguages={this.state.siteRes.all_languages}
+ siteLanguages={this.state.siteRes.discussion_languages}
+ />
+ </div>
+ )
+ );
}
sidebar() {
- return this.state.postRes.match({
- some: res => (
+ let res = this.state.postRes;
+ return (
+ res && (
<div className="mb-3">
<Sidebar
community_view={res.community_view}
showIcon
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
- communityLanguages={None}
/>
</div>
- ),
- none: <></>,
- });
+ )
+ );
}
handleCommentSortChange(i: Post, event: any) {
}
handleCommentViewTypeChange(i: Post, event: any) {
- i.setState({
- commentViewType: Number(event.target.value),
- commentSort: CommentSortType.New,
- commentTree: buildCommentsTree(
- i.state.commentsRes.map(r => r.comments).unwrapOr([]),
- i.state.commentId.isSome()
- ),
- });
+ let comments = i.state.commentsRes?.comments;
+ if (comments) {
+ i.setState({
+ commentViewType: Number(event.target.value),
+ commentSort: CommentSortType.New,
+ commentTree: buildCommentsTree(comments, !!i.state.commentId),
+ });
+ }
}
handleShowSidebarMobile(i: Post) {
}
handleViewPost(i: Post) {
- i.state.postRes.match({
- some: res =>
- i.context.router.history.push(`/post/${res.post_view.post.id}`),
- none: void 0,
- });
+ let id = i.state.postRes?.post_view.post.id;
+ if (id) {
+ i.context.router.history.push(`/post/${id}`);
+ }
}
handleViewContext(i: Post) {
- i.state.commentsRes.match({
- some: res =>
- i.context.router.history.push(
- `/comment/${getCommentParentId(res.comments[0].comment).unwrap()}`
- ),
- none: void 0,
- });
+ let parentId = getCommentParentId(
+ i.state.commentsRes?.comments?.at(0)?.comment
+ );
+ if (parentId) {
+ i.context.router.history.push(`/comment/${parentId}`);
+ }
}
commentsTree() {
- let showContextButton = toOption(this.state.commentTree[0]).match({
- some: comment => getDepthFromComment(comment.comment_view.comment) > 0,
- none: false,
- });
+ let res = this.state.postRes;
+ let firstComment = this.state.commentTree.at(0)?.comment_view.comment;
+ let depth = getDepthFromComment(firstComment);
+ let showContextButton = depth ? depth > 0 : false;
- return this.state.postRes.match({
- some: res => (
+ return (
+ res && (
<div>
- {this.state.commentId.isSome() && (
+ {!!this.state.commentId && (
<>
<button
className="pl-0 d-block btn btn-link text-muted"
<CommentNodes
nodes={this.state.commentTree}
viewType={this.state.commentViewType}
- maxCommentsShown={Some(this.state.maxCommentsShown)}
+ maxCommentsShown={this.state.maxCommentsShown}
locked={res.post_view.post.locked}
- moderators={Some(res.moderators)}
- admins={Some(this.state.siteRes.admins)}
+ moderators={res.moderators}
+ admins={this.state.siteRes.admins}
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
/>
</div>
- ),
- none: <></>,
- });
+ )
+ );
}
parseMessage(msg: any) {
toast(i18n.t(msg.error), "danger");
return;
} else if (msg.reconnect) {
- this.state.postRes.match({
- some: res => {
- let postId = res.post_view.post.id;
- WebSocketService.Instance.send(
- wsClient.postJoin({ post_id: postId })
- );
- WebSocketService.Instance.send(
- wsClient.getPost({
- id: Some(postId),
- comment_id: None,
- auth: auth(false).ok(),
- })
- );
- },
- none: void 0,
- });
+ let post_id = this.state.postRes?.post_view.post.id;
+ if (post_id) {
+ WebSocketService.Instance.send(wsClient.postJoin({ post_id }));
+ WebSocketService.Instance.send(
+ wsClient.getPost({
+ id: post_id,
+ auth: myAuth(false),
+ })
+ );
+ }
} else if (op == UserOperation.GetPost) {
- let data = wsJsonToRes<GetPostResponse>(msg, GetPostResponse);
- this.setState({ postRes: Some(data) });
+ let data = wsJsonToRes<GetPostResponse>(msg);
+ this.setState({ postRes: data });
// join the rooms
WebSocketService.Instance.send(
// TODO move this into initial fetch and refetch
this.fetchCrossPosts();
setupTippy();
- if (this.state.commentId.isNone()) restoreScrollPosition(this.context);
+ if (!this.state.commentId) restoreScrollPosition(this.context);
if (this.checkScrollIntoCommentsParam) {
this.scrollIntoCommentSection();
}
} else if (op == UserOperation.GetComments) {
- let data = wsJsonToRes<GetCommentsResponse>(msg, GetCommentsResponse);
- // You might need to append here, since this could be building more comments from a tree fetch
- this.state.commentsRes.match({
- some: res => {
- // Remove the first comment, since it is the parent
- let newComments = data.comments;
- newComments.shift();
- res.comments.push(...newComments);
- },
- none: () => this.setState({ commentsRes: Some(data) }),
- });
- // this.state.commentsRes = Some(data);
+ let data = wsJsonToRes<GetCommentsResponse>(msg);
+ // This section sets the comments res
+ let comments = this.state.commentsRes?.comments;
+ if (comments) {
+ // You might need to append here, since this could be building more comments from a tree fetch
+ // Remove the first comment, since it is the parent
+ let newComments = data.comments;
+ newComments.shift();
+ comments.push(...newComments);
+ } else {
+ this.setState({ commentsRes: data });
+ }
+
+ let cComments = this.state.commentsRes?.comments ?? [];
this.setState({
- commentTree: buildCommentsTree(
- this.state.commentsRes.map(r => r.comments).unwrapOr([]),
- this.state.commentId.isSome()
- ),
+ commentTree: buildCommentsTree(cComments, !!this.state.commentId),
loading: false,
});
- this.setState(this.state);
} else if (op == UserOperation.CreateComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
// Don't get comments from the post room, if the creator is blocked
- let creatorBlocked = UserService.Instance.myUserInfo
- .map(m => m.person_blocks)
- .unwrapOr([])
+ let creatorBlocked = UserService.Instance.myUserInfo?.person_blocks
.map(pb => pb.target.id)
.includes(data.comment_view.creator.id);
// Necessary since it might be a user reply, which has the recipients, to avoid double
- if (data.recipient_ids.length == 0 && !creatorBlocked) {
- this.state.postRes.match({
- some: postRes =>
- this.state.commentsRes.match({
- some: commentsRes => {
- commentsRes.comments.unshift(data.comment_view);
- insertCommentIntoTree(
- this.state.commentTree,
- data.comment_view,
- this.state.commentId.isSome()
- );
- postRes.post_view.counts.comments++;
- },
- none: void 0,
- }),
- none: void 0,
- });
+ let postRes = this.state.postRes;
+ let commentsRes = this.state.commentsRes;
+ if (
+ data.recipient_ids.length == 0 &&
+ !creatorBlocked &&
+ postRes &&
+ commentsRes
+ ) {
+ commentsRes.comments.unshift(data.comment_view);
+ insertCommentIntoTree(
+ this.state.commentTree,
+ data.comment_view,
+ !!this.state.commentId
+ );
+ postRes.post_view.counts.comments++;
+
this.setState(this.state);
setupTippy();
}
op == UserOperation.DeleteComment ||
op == UserOperation.RemoveComment
) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- editCommentRes(
- data.comment_view,
- this.state.commentsRes.map(r => r.comments).unwrapOr([])
- );
+ let data = wsJsonToRes<CommentResponse>(msg);
+ editCommentRes(data.comment_view, this.state.commentsRes?.comments);
this.setState(this.state);
setupTippy();
} else if (op == UserOperation.SaveComment) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- saveCommentRes(
- data.comment_view,
- this.state.commentsRes.map(r => r.comments).unwrapOr([])
- );
+ let data = wsJsonToRes<CommentResponse>(msg);
+ saveCommentRes(data.comment_view, this.state.commentsRes?.comments);
this.setState(this.state);
setupTippy();
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
- createCommentLikeRes(
- data.comment_view,
- this.state.commentsRes.map(r => r.comments).unwrapOr([])
- );
+ let data = wsJsonToRes<CommentResponse>(msg);
+ createCommentLikeRes(data.comment_view, this.state.commentsRes?.comments);
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- this.state.postRes.match({
- some: res => createPostLikeRes(data.post_view, res.post_view),
- none: void 0,
- });
+ let data = wsJsonToRes<PostResponse>(msg);
+ createPostLikeRes(data.post_view, this.state.postRes?.post_view);
this.setState(this.state);
} else if (
op == UserOperation.EditPost ||
op == UserOperation.FeaturePost ||
op == UserOperation.SavePost
) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- this.state.postRes.match({
- some: res => (res.post_view = data.post_view),
- none: void 0,
- });
- this.setState(this.state);
- setupTippy();
+ let data = wsJsonToRes<PostResponse>(msg);
+ let pv = this.state.postRes?.post_view;
+ if (pv) {
+ pv = data.post_view;
+ this.setState(this.state);
+ setupTippy();
+ }
} else if (
op == UserOperation.EditCommunity ||
op == UserOperation.DeleteCommunity ||
op == UserOperation.RemoveCommunity ||
op == UserOperation.FollowCommunity
) {
- let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
- this.state.postRes.match({
- some: res => {
- res.community_view = data.community_view;
- res.post_view.community = data.community_view.community;
- this.setState(this.state);
- },
- none: void 0,
- });
+ let data = wsJsonToRes<CommunityResponse>(msg);
+ let res = this.state.postRes;
+ if (res) {
+ res.community_view = data.community_view;
+ res.post_view.community = data.community_view.community;
+ this.setState(this.state);
+ }
} else if (op == UserOperation.BanFromCommunity) {
- let data = wsJsonToRes<BanFromCommunityResponse>(
- msg,
- BanFromCommunityResponse
- );
- this.state.postRes.match({
- some: postRes =>
- this.state.commentsRes.match({
- some: commentsRes => {
- commentsRes.comments
- .filter(c => c.creator.id == data.person_view.person.id)
- .forEach(c => (c.creator_banned_from_community = data.banned));
- if (postRes.post_view.creator.id == data.person_view.person.id) {
- postRes.post_view.creator_banned_from_community = data.banned;
- }
- this.setState(this.state);
- },
- none: void 0,
- }),
- none: void 0,
- });
+ let data = wsJsonToRes<BanFromCommunityResponse>(msg);
+
+ let postRes = this.state.postRes;
+ if (postRes) {
+ if (postRes.post_view.creator.id == data.person_view.person.id) {
+ postRes.post_view.creator_banned_from_community = data.banned;
+ }
+ }
+
+ this.state.commentsRes?.comments
+ .filter(c => c.creator.id == data.person_view.person.id)
+ .forEach(c => (c.creator_banned_from_community = data.banned));
+ this.setState(this.state);
} else if (op == UserOperation.AddModToCommunity) {
- let data = wsJsonToRes<AddModToCommunityResponse>(
- msg,
- AddModToCommunityResponse
- );
- this.state.postRes.match({
- some: res => {
- res.moderators = data.moderators;
- this.setState(this.state);
- },
- none: void 0,
- });
+ let data = wsJsonToRes<AddModToCommunityResponse>(msg);
+ let postRes = this.state.postRes;
+ if (postRes) {
+ postRes.moderators = data.moderators;
+ this.setState(this.state);
+ }
} else if (op == UserOperation.BanPerson) {
- let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
- this.state.postRes.match({
- some: postRes =>
- this.state.commentsRes.match({
- some: commentsRes => {
- commentsRes.comments
- .filter(c => c.creator.id == data.person_view.person.id)
- .forEach(c => (c.creator.banned = data.banned));
- if (postRes.post_view.creator.id == data.person_view.person.id) {
- postRes.post_view.creator.banned = data.banned;
- }
- this.setState(this.state);
- },
- none: void 0,
- }),
- none: void 0,
- });
+ let data = wsJsonToRes<BanPersonResponse>(msg);
+ this.state.commentsRes?.comments
+ .filter(c => c.creator.id == data.person_view.person.id)
+ .forEach(c => (c.creator.banned = data.banned));
+
+ let postRes = this.state.postRes;
+ if (postRes) {
+ if (postRes.post_view.creator.id == data.person_view.person.id) {
+ postRes.post_view.creator.banned = data.banned;
+ }
+ }
+ this.setState(this.state);
} else if (op == UserOperation.AddAdmin) {
- let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
+ let data = wsJsonToRes<AddAdminResponse>(msg);
this.setState(s => ((s.siteRes.admins = data.admins), s));
} else if (op == UserOperation.Search) {
- let data = wsJsonToRes<SearchResponse>(msg, SearchResponse);
+ let data = wsJsonToRes<SearchResponse>(msg);
let xPosts = data.posts.filter(
p => p.post.id != Number(this.props.match.params.id)
);
- this.setState({ crossPosts: xPosts.length > 0 ? Some(xPosts) : None });
+ this.setState({ crossPosts: xPosts.length > 0 ? xPosts : undefined });
} else if (op == UserOperation.LeaveAdmin) {
- let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+ let data = wsJsonToRes<GetSiteResponse>(msg);
this.setState({ siteRes: data });
} else if (op == UserOperation.TransferCommunity) {
- let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
- this.state.postRes.match({
- some: res => {
- res.community_view = data.community_view;
- res.post_view.community = data.community_view.community;
- res.moderators = data.moderators;
- this.setState(this.state);
- },
- none: void 0,
- });
+ let data = wsJsonToRes<GetCommunityResponse>(msg);
+ let postRes = this.state.postRes;
+ if (postRes) {
+ postRes.community_view = data.community_view;
+ postRes.post_view.community = data.community_view.community;
+ postRes.moderators = data.moderators;
+ this.setState(this.state);
+ }
} else if (op == UserOperation.BlockPerson) {
- let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
+ let data = wsJsonToRes<BlockPersonResponse>(msg);
updatePersonBlock(data);
} else if (op == UserOperation.CreatePostReport) {
- let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+ let data = wsJsonToRes<PostReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
} else if (op == UserOperation.CreateCommentReport) {
- let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+ let data = wsJsonToRes<CommentReportResponse>(msg);
if (data) {
toast(i18n.t("report_created"));
}
op == UserOperation.PurgeComment ||
op == UserOperation.PurgeCommunity
) {
- let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+ let data = wsJsonToRes<PurgeItemResponse>(msg);
if (data.success) {
toast(i18n.t("purge_success"));
this.context.router.history.push(`/`);
-import { None, Option, Some } from "@sniptt/monads";
import { Component } from "inferno";
import {
GetPersonDetails,
import { InitialFetchRequest } from "../../interfaces";
import { UserService, WebSocketService } from "../../services";
import {
- auth,
getRecipientIdFromProps,
isBrowser,
+ myAuth,
setIsoData,
toast,
wsClient,
interface CreatePrivateMessageState {
siteRes: GetSiteResponse;
- recipientDetailsRes: Option<GetPersonDetailsResponse>;
+ recipientDetailsRes?: GetPersonDetailsResponse;
recipient_id: number;
loading: boolean;
}
any,
CreatePrivateMessageState
> {
- private isoData = setIsoData(this.context, GetPersonDetailsResponse);
- private subscription: Subscription;
- private emptyState: CreatePrivateMessageState = {
+ private isoData = setIsoData(this.context);
+ private subscription?: Subscription;
+ state: CreatePrivateMessageState = {
siteRes: this.isoData.site_res,
- recipientDetailsRes: None,
recipient_id: getRecipientIdFromProps(this.props),
loading: true,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handlePrivateMessageCreate =
this.handlePrivateMessageCreate.bind(this);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
- if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+ if (!UserService.Instance.myUserInfo && isBrowser()) {
toast(i18n.t("not_logged_in"), "danger");
this.context.router.history.push(`/login`);
}
if (this.isoData.path == this.context.router.route.match.url) {
this.state = {
...this.state,
- recipientDetailsRes: Some(
- this.isoData.routeData[0] as GetPersonDetailsResponse
- ),
+ recipientDetailsRes: this.isoData
+ .routeData[0] as GetPersonDetailsResponse,
loading: false,
};
} else {
}
fetchPersonDetails() {
- let form = new GetPersonDetails({
- person_id: Some(this.state.recipient_id),
- sort: Some(SortType.New),
- saved_only: Some(false),
- username: None,
- page: None,
- limit: None,
- community_id: None,
- auth: auth(false).ok(),
- });
+ let form: GetPersonDetails = {
+ person_id: this.state.recipient_id,
+ sort: SortType.New,
+ saved_only: false,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(wsClient.getPersonDetails(form));
}
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
- let person_id = Some(Number(req.path.split("/").pop()));
- let form = new GetPersonDetails({
+ let person_id = Number(req.path.split("/").pop());
+ let form: GetPersonDetails = {
person_id,
- sort: Some(SortType.New),
- saved_only: Some(false),
- username: None,
- page: None,
- limit: None,
- community_id: None,
+ sort: SortType.New,
+ saved_only: false,
auth: req.auth,
- });
+ };
return [req.client.getPersonDetails(form)];
}
get documentTitle(): string {
- return this.state.recipientDetailsRes.match({
- some: res =>
- `${i18n.t("create_private_message")} - ${res.person_view.person.name}`,
- none: "",
- });
+ let name_ = this.state.recipientDetailsRes?.person_view.person.name;
+ return name_ ? `${i18n.t("create_private_message")} - ${name_}` : "";
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
}
}
render() {
+ let res = this.state.recipientDetailsRes;
return (
<div className="container-lg">
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
{this.state.loading ? (
<h5>
<Spinner large />
</h5>
) : (
- this.state.recipientDetailsRes.match({
- some: res => (
- <div className="row">
- <div className="col-12 col-lg-6 offset-lg-3 mb-4">
- <h5>{i18n.t("create_private_message")}</h5>
- <PrivateMessageForm
- privateMessageView={None}
- onCreate={this.handlePrivateMessageCreate}
- recipient={res.person_view.person}
- />
- </div>
+ res && (
+ <div className="row">
+ <div className="col-12 col-lg-6 offset-lg-3 mb-4">
+ <h5>{i18n.t("create_private_message")}</h5>
+ <PrivateMessageForm
+ onCreate={this.handlePrivateMessageCreate}
+ recipient={res.person_view.person}
+ />
</div>
- ),
- none: <></>,
- })
+ </div>
+ )
)}
</div>
);
this.setState({ loading: false });
return;
} else if (op == UserOperation.GetPersonDetails) {
- let data = wsJsonToRes<GetPersonDetailsResponse>(
- msg,
- GetPersonDetailsResponse
- );
- this.setState({ recipientDetailsRes: Some(data), loading: false });
+ let data = wsJsonToRes<GetPersonDetailsResponse>(msg);
+ this.setState({ recipientDetailsRes: data, loading: false });
}
}
}
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import { T } from "inferno-i18next-dess";
import { Prompt } from "inferno-router";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
import {
- auth,
capitalizeFirstLetter,
isBrowser,
+ myAuth,
relTags,
setupTippy,
toast,
interface PrivateMessageFormProps {
recipient: PersonSafe;
- privateMessageView: Option<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
onCancel?(): any;
onCreate?(message: PrivateMessageView): any;
onEdit?(message: PrivateMessageView): any;
}
interface PrivateMessageFormState {
- privateMessageForm: CreatePrivateMessage;
+ content?: string;
loading: boolean;
previewMode: boolean;
showDisclaimer: boolean;
PrivateMessageFormProps,
PrivateMessageFormState
> {
- private subscription: Subscription;
- private emptyState: PrivateMessageFormState = {
- privateMessageForm: new CreatePrivateMessage({
- content: null,
- recipient_id: this.props.recipient.id,
- auth: auth().unwrap(),
- }),
+ private subscription?: Subscription;
+ state: PrivateMessageFormState = {
loading: false,
previewMode: false,
showDisclaimer: false,
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
-
this.handleContentChange = this.handleContentChange.bind(this);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
// Its an edit
- if (this.props.privateMessageView.isSome()) {
- this.state.privateMessageForm.content =
- this.props.privateMessageView.unwrap().private_message.content;
+ if (this.props.privateMessageView) {
+ this.state.content =
+ this.props.privateMessageView.private_message.content;
}
}
}
componentDidUpdate() {
- if (!this.state.loading && this.state.privateMessageForm.content) {
+ if (!this.state.loading && this.state.content) {
window.onbeforeunload = () => true;
} else {
- window.onbeforeunload = undefined;
+ window.onbeforeunload = null;
}
}
componentWillUnmount() {
if (isBrowser()) {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
window.onbeforeunload = null;
}
}
return (
<div>
<Prompt
- when={!this.state.loading && this.state.privateMessageForm.content}
+ when={!this.state.loading && this.state.content}
message={i18n.t("block_leaving")}
/>
<form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
- {this.props.privateMessageView.isNone() && (
+ {!this.props.privateMessageView && (
<div className="form-group row">
<label className="col-sm-2 col-form-label">
{capitalizeFirstLetter(i18n.t("to"))}
</label>
<div className="col-sm-10">
<MarkdownTextArea
- initialContent={Some(this.state.privateMessageForm.content)}
- initialLanguageId={None}
- placeholder={None}
- buttonTitle={None}
- maxLength={None}
+ initialContent={this.state.content}
onContentChange={this.handleContentChange}
allLanguages={[]}
siteLanguages={[]}
>
{this.state.loading ? (
<Spinner />
- ) : this.props.privateMessageView.isSome() ? (
+ ) : this.props.privateMessageView ? (
capitalizeFirstLetter(i18n.t("save"))
) : (
capitalizeFirstLetter(i18n.t("send_message"))
)}
</button>
- {this.props.privateMessageView.isSome() && (
+ {this.props.privateMessageView && (
<button
type="button"
className="btn btn-secondary"
handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
event.preventDefault();
- i.props.privateMessageView.match({
- some: pm => {
- let form = new EditPrivateMessage({
+ let pm = i.props.privateMessageView;
+ let auth = myAuth();
+ let content = i.state.content;
+ if (auth && content) {
+ if (pm) {
+ let form: EditPrivateMessage = {
private_message_id: pm.private_message.id,
- content: i.state.privateMessageForm.content,
- auth: auth().unwrap(),
- });
+ content,
+ auth,
+ };
WebSocketService.Instance.send(wsClient.editPrivateMessage(form));
- },
- none: WebSocketService.Instance.send(
- wsClient.createPrivateMessage(i.state.privateMessageForm)
- ),
- });
- i.setState({ loading: true });
+ } else {
+ let form: CreatePrivateMessage = {
+ content,
+ recipient_id: i.props.recipient.id,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.createPrivateMessage(form));
+ }
+ i.setState({ loading: true });
+ }
}
handleContentChange(val: string) {
- this.setState(s => ((s.privateMessageForm.content = val), s));
+ this.setState({ content: val });
}
handleCancel(i: PrivateMessageForm) {
- i.props.onCancel();
+ i.props.onCancel?.();
}
handlePreviewToggle(i: PrivateMessageForm, event: any) {
op == UserOperation.DeletePrivateMessage ||
op == UserOperation.MarkPrivateMessageAsRead
) {
- let data = wsJsonToRes<PrivateMessageResponse>(
- msg,
- PrivateMessageResponse
- );
+ let data = wsJsonToRes<PrivateMessageResponse>(msg);
this.setState({ loading: false });
- this.props.onEdit(data.private_message_view);
+ this.props.onEdit?.(data.private_message_view);
} else if (op == UserOperation.CreatePrivateMessage) {
- let data = wsJsonToRes<PrivateMessageResponse>(
- msg,
- PrivateMessageResponse
- );
- this.props.onCreate(data.private_message_view);
+ let data = wsJsonToRes<PrivateMessageResponse>(msg);
+ this.props.onCreate?.(data.private_message_view);
}
}
}
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { WebSocketService } from "../../services";
-import { auth, mdToHtml, wsClient } from "../../utils";
+import { mdToHtml, myAuth, wsClient } from "../../utils";
import { Icon } from "../common/icon";
import { PersonListing } from "../person/person-listing";
<div>
{i18n.t("reason")}: {pmr.reason}
</div>
- {r.resolver.match({
- some: resolver => (
- <div>
- {pmr.resolved ? (
- <T i18nKey="resolved_by">
- #
- <PersonListing person={resolver} />
- </T>
- ) : (
- <T i18nKey="unresolved_by">
- #
- <PersonListing person={resolver} />
- </T>
- )}
- </div>
- ),
- none: <></>,
- })}
+ {r.resolver && (
+ <div>
+ {pmr.resolved ? (
+ <T i18nKey="resolved_by">
+ #
+ <PersonListing person={r.resolver} />
+ </T>
+ ) : (
+ <T i18nKey="unresolved_by">
+ #
+ <PersonListing person={r.resolver} />
+ </T>
+ )}
+ </div>
+ )}
<button
className="btn btn-link btn-animate text-muted py-0"
onClick={linkEvent(this, this.handleResolveReport)}
handleResolveReport(i: PrivateMessageReport) {
let pmr = i.props.report.private_message_report;
- let form = new ResolvePrivateMessageReport({
- report_id: pmr.id,
- resolved: !pmr.resolved,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.resolvePrivateMessageReport(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: ResolvePrivateMessageReport = {
+ report_id: pmr.id,
+ resolved: !pmr.resolved,
+ auth,
+ };
+ WebSocketService.Instance.send(
+ wsClient.resolvePrivateMessageReport(form)
+ );
+ }
}
}
-import { None, Option, Some } from "@sniptt/monads/build";
import { Component, linkEvent } from "inferno";
import {
CreatePrivateMessageReport,
MarkPrivateMessageAsRead,
PersonSafe,
PrivateMessageView,
- toUndefined,
} from "lemmy-js-client";
import { i18n } from "../../i18next";
import { UserService, WebSocketService } from "../../services";
-import { auth, mdToHtml, toast, wsClient } from "../../utils";
+import { mdToHtml, myAuth, toast, wsClient } from "../../utils";
import { Icon } from "../common/icon";
import { MomentTime } from "../common/moment-time";
import { PersonListing } from "../person/person-listing";
collapsed: boolean;
viewSource: boolean;
showReportDialog: boolean;
- reportReason: Option<string>;
+ reportReason?: string;
}
interface PrivateMessageProps {
PrivateMessageProps,
PrivateMessageState
> {
- private emptyState: PrivateMessageState = {
+ state: PrivateMessageState = {
showReply: false,
showEdit: false,
collapsed: false,
viewSource: false,
showReportDialog: false,
- reportReason: None,
};
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleReplyCancel = this.handleReplyCancel.bind(this);
this.handlePrivateMessageCreate =
this.handlePrivateMessageCreate.bind(this);
}
get mine(): boolean {
- return UserService.Instance.myUserInfo
- .map(
- m =>
- m.local_user_view.person.id ==
- this.props.private_message_view.creator.id
- )
- .unwrapOr(false);
+ return (
+ UserService.Instance.myUserInfo?.local_user_view.person.id ==
+ this.props.private_message_view.creator.id
+ );
}
render() {
{this.state.showEdit && (
<PrivateMessageForm
recipient={otherPerson}
- privateMessageView={Some(message_view)}
+ privateMessageView={message_view}
onEdit={this.handlePrivateMessageEdit}
onCreate={this.handlePrivateMessageCreate}
onCancel={this.handleReplyCancel}
className="form-control mr-2"
placeholder={i18n.t("reason")}
required
- value={toUndefined(this.state.reportReason)}
+ value={this.state.reportReason}
onInput={linkEvent(this, this.handleReportReasonChange)}
/>
<button
{this.state.showReply && (
<PrivateMessageForm
recipient={otherPerson}
- privateMessageView={None}
onCreate={this.handlePrivateMessageCreate}
/>
)}
}
handleDeleteClick(i: PrivateMessage) {
- let form = new DeletePrivateMessage({
- private_message_id: i.props.private_message_view.private_message.id,
- deleted: !i.props.private_message_view.private_message.deleted,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.deletePrivateMessage(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: DeletePrivateMessage = {
+ private_message_id: i.props.private_message_view.private_message.id,
+ deleted: !i.props.private_message_view.private_message.deleted,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.deletePrivateMessage(form));
+ }
}
handleReplyCancel() {
}
handleMarkRead(i: PrivateMessage) {
- let form = new MarkPrivateMessageAsRead({
- private_message_id: i.props.private_message_view.private_message.id,
- read: !i.props.private_message_view.private_message.read,
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.markPrivateMessageAsRead(form));
+ let auth = myAuth();
+ if (auth) {
+ let form: MarkPrivateMessageAsRead = {
+ private_message_id: i.props.private_message_view.private_message.id,
+ read: !i.props.private_message_view.private_message.read,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.markPrivateMessageAsRead(form));
+ }
}
handleMessageCollapse(i: PrivateMessage) {
}
handleReportReasonChange(i: PrivateMessage, event: any) {
- i.setState({ reportReason: Some(event.target.value) });
+ i.setState({ reportReason: event.target.value });
}
handleReportSubmit(i: PrivateMessage, event: any) {
event.preventDefault();
- let form = new CreatePrivateMessageReport({
- private_message_id: i.props.private_message_view.private_message.id,
- reason: toUndefined(i.state.reportReason),
- auth: auth().unwrap(),
- });
- WebSocketService.Instance.send(wsClient.createPrivateMessageReport(form));
+ let auth = myAuth();
+ let reason = i.state.reportReason;
+ if (auth && reason) {
+ let form: CreatePrivateMessageReport = {
+ private_message_id: i.props.private_message_view.private_message.id,
+ reason,
+ auth,
+ };
+ WebSocketService.Instance.send(wsClient.createPrivateMessageReport(form));
- i.setState({ showReportDialog: false });
+ i.setState({ showReportDialog: false });
+ }
}
handlePrivateMessageEdit() {
}
handlePrivateMessageCreate(message: PrivateMessageView) {
- UserService.Instance.myUserInfo.match({
- some: mui => {
- if (message.creator.id == mui.local_user_view.person.id) {
- this.setState({ showReply: false });
- toast(i18n.t("message_sent"));
- }
- },
- none: void 0,
- });
+ if (
+ message.creator.id ==
+ UserService.Instance.myUserInfo?.local_user_view.person.id
+ ) {
+ this.setState({ showReply: false });
+ toast(i18n.t("message_sent"));
+ }
}
}
-import { None, Option, Some } from "@sniptt/monads";
import { Component, linkEvent } from "inferno";
import {
CommentResponse,
import { CommentViewType, InitialFetchRequest } from "../interfaces";
import { WebSocketService } from "../services";
import {
- auth,
capitalizeFirstLetter,
choicesConfig,
commentsToFlatNodes,
fetchLimit,
fetchUsers,
isBrowser,
+ myAuth,
numToSI,
personSelectName,
personToChoice,
communityId: number;
creatorId: number;
page: number;
- searchResponse: Option<SearchResponse>;
+ searchResponse?: SearchResponse;
communities: CommunityView[];
- creatorDetails: Option<GetPersonDetailsResponse>;
+ creatorDetails?: GetPersonDetailsResponse;
loading: boolean;
siteRes: GetSiteResponse;
searchText: string;
- resolveObjectResponse: Option<ResolveObjectResponse>;
+ resolveObjectResponse?: ResolveObjectResponse;
}
interface UrlParams {
}
export class Search extends Component<any, SearchState> {
- private isoData = setIsoData(
- this.context,
- GetCommunityResponse,
- ListCommunitiesResponse,
- GetPersonDetailsResponse,
- SearchResponse,
- ResolveObjectResponse
- );
+ private isoData = setIsoData(this.context);
private communityChoices: any;
private creatorChoices: any;
- private subscription: Subscription;
- private emptyState: SearchState = {
+ private subscription?: Subscription;
+ state: SearchState = {
q: Search.getSearchQueryFromProps(this.props.match.params.q),
type_: Search.getSearchTypeFromProps(this.props.match.params.type),
sort: Search.getSortTypeFromProps(this.props.match.params.sort),
this.props.match.params.community_id
),
creatorId: Search.getCreatorIdFromProps(this.props.match.params.creator_id),
- searchResponse: None,
- resolveObjectResponse: None,
- creatorDetails: None,
loading: true,
siteRes: this.isoData.site_res,
communities: [],
constructor(props: any, context: any) {
super(props, context);
- this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this);
this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
this.handlePageChange = this.handlePageChange.bind(this);
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
- let communityRes = Some(
- this.isoData.routeData[0] as GetCommunityResponse
- );
- let communitiesRes = Some(
- this.isoData.routeData[1] as ListCommunitiesResponse
- );
-
+ let communityRes = this.isoData.routeData[0] as
+ | GetCommunityResponse
+ | undefined;
+ let communitiesRes = this.isoData.routeData[1] as
+ | ListCommunitiesResponse
+ | undefined;
// This can be single or multiple communities given
- if (communitiesRes.isSome()) {
+ if (communitiesRes) {
this.state = {
...this.state,
- communities: communitiesRes.unwrap().communities,
+ communities: communitiesRes.communities,
};
}
- if (communityRes.isSome()) {
+ if (communityRes) {
this.state = {
...this.state,
- communities: [communityRes.unwrap().community_view],
+ communities: [communityRes.community_view],
};
}
this.state = {
...this.state,
- creatorDetails: Some(
- this.isoData.routeData[2] as GetPersonDetailsResponse
- ),
+ creatorDetails: this.isoData.routeData[2] as GetPersonDetailsResponse,
};
if (this.state.q != "") {
this.state = {
...this.state,
- searchResponse: Some(this.isoData.routeData[3] as SearchResponse),
- resolveObjectResponse: Some(
- this.isoData.routeData[4] as ResolveObjectResponse
- ),
+ searchResponse: this.isoData.routeData[3] as SearchResponse,
+ resolveObjectResponse: this.isoData
+ .routeData[4] as ResolveObjectResponse,
loading: false,
};
} else {
}
componentWillUnmount() {
- this.subscription.unsubscribe();
+ this.subscription?.unsubscribe();
saveScrollPosition(this.context);
}
}
fetchCommunities() {
- let listCommunitiesForm = new ListCommunities({
- type_: Some(ListingType.All),
- sort: Some(SortType.TopAll),
- limit: Some(fetchLimit),
- page: None,
- auth: auth(false).ok(),
- });
+ let listCommunitiesForm: ListCommunities = {
+ type_: ListingType.All,
+ sort: SortType.TopAll,
+ limit: fetchLimit,
+ auth: myAuth(false),
+ };
WebSocketService.Instance.send(
wsClient.listCommunities(listCommunitiesForm)
);
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
let pathSplit = req.path.split("/");
let promises: Promise<any>[] = [];
+ let auth = req.auth;
let communityId = this.getCommunityIdFromProps(pathSplit[11]);
- let community_id: Option<number> =
- communityId == 0 ? None : Some(communityId);
- community_id.match({
- some: id => {
- let getCommunityForm = new GetCommunity({
- id: Some(id),
- name: None,
- auth: req.auth,
- });
- promises.push(req.client.getCommunity(getCommunityForm));
- promises.push(Promise.resolve());
- },
- none: () => {
- let listCommunitiesForm = new ListCommunities({
- type_: Some(ListingType.All),
- sort: Some(SortType.TopAll),
- limit: Some(fetchLimit),
- page: None,
- auth: req.auth,
- });
- promises.push(Promise.resolve());
- promises.push(req.client.listCommunities(listCommunitiesForm));
- },
- });
+ let community_id = communityId == 0 ? undefined : communityId;
+ if (community_id) {
+ let getCommunityForm: GetCommunity = {
+ id: community_id,
+ auth,
+ };
+ promises.push(req.client.getCommunity(getCommunityForm));
+ promises.push(Promise.resolve());
+ } else {
+ let listCommunitiesForm: ListCommunities = {
+ type_: ListingType.All,
+ sort: SortType.TopAll,
+ limit: fetchLimit,
+ auth: req.auth,
+ };
+ promises.push(Promise.resolve());
+ promises.push(req.client.listCommunities(listCommunitiesForm));
+ }
let creatorId = this.getCreatorIdFromProps(pathSplit[13]);
- let creator_id: Option<number> = creatorId == 0 ? None : Some(creatorId);
- creator_id.match({
- some: id => {
- let getCreatorForm = new GetPersonDetails({
- person_id: Some(id),
- username: None,
- sort: None,
- page: None,
- limit: None,
- community_id: None,
- saved_only: None,
- auth: req.auth,
- });
- promises.push(req.client.getPersonDetails(getCreatorForm));
- },
- none: () => {
- promises.push(Promise.resolve());
- },
- });
+ let creator_id = creatorId == 0 ? undefined : creatorId;
+ if (creator_id) {
+ let getCreatorForm: GetPersonDetails = {
+ person_id: creator_id,
+ auth: req.auth,
+ };
+ promises.push(req.client.getPersonDetails(getCreatorForm));
+ } else {
+ promises.push(Promise.resolve());
+ }
- let form = new SearchForm({
+ let form: SearchForm = {
q: this.getSearchQueryFromProps(pathSplit[3]),
community_id,
- community_name: None,
creator_id,
- type_: Some(this.getSearchTypeFromProps(pathSplit[5])),
- sort: Some(this.getSortTypeFromProps(pathSplit[7])),
- listing_type: Some(this.getListingTypeFromProps(pathSplit[9])),
- page: Some(this.getPageFromProps(pathSplit[15])),
- limit: Some(fetchLimit),
+ type_: this.getSearchTypeFromProps(pathSplit[5]),
+ sort: this.getSortTypeFromProps(pathSplit[7]),
+ listing_type: this.getListingTypeFromProps(pathSplit[9]),
+ page: this.getPageFromProps(pathSplit[15]),
+ limit: fetchLimit,
auth: req.auth,
- });
+ };
- let resolveObjectForm = new ResolveObject({
+ let resolveObjectForm: ResolveObject = {
q: this.getSearchQueryFromProps(pathSplit[3]),
auth: req.auth,
- });
+ };
if (form.q != "") {
promises.push(req.client.search(form));
this.setState({
loading: true,
searchText: this.state.q,
- searchResponse: None,
- resolveObjectResponse: None,
});
this.search();
}
<HtmlTags
title={this.documentTitle}
path={this.context.router.route.match.url}
- description={None}
- image={None}
/>
<h5>{i18n.t("search")}</h5>
{this.selects()}
buildCombined(): Combined[] {
let combined: Combined[] = [];
+ let resolveRes = this.state.resolveObjectResponse;
// Push the possible resolve / federated objects first
- this.state.resolveObjectResponse.match({
- some: res => {
- let resolveComment = res.comment;
- if (resolveComment.isSome()) {
- combined.push(this.commentViewToCombined(resolveComment.unwrap()));
- }
- let resolvePost = res.post;
- if (resolvePost.isSome()) {
- combined.push(this.postViewToCombined(resolvePost.unwrap()));
- }
- let resolveCommunity = res.community;
- if (resolveCommunity.isSome()) {
- combined.push(
- this.communityViewToCombined(resolveCommunity.unwrap())
- );
- }
- let resolveUser = res.person;
- if (resolveUser.isSome()) {
- combined.push(this.personViewSafeToCombined(resolveUser.unwrap()));
- }
- },
- none: void 0,
- });
+ if (resolveRes) {
+ let resolveComment = resolveRes.comment;
+ if (resolveComment) {
+ combined.push(this.commentViewToCombined(resolveComment));
+ }
+ let resolvePost = resolveRes.post;
+ if (resolvePost) {
+ combined.push(this.postViewToCombined(resolvePost));
+ }
+ let resolveCommunity = resolveRes.community;
+ if (resolveCommunity) {
+ combined.push(this.communityViewToCombined(resolveCommunity));
+ }
+ let resolveUser = resolveRes.person;
+ if (resolveUser) {
+ combined.push(this.personViewSafeToCombined(resolveUser));
+ }
+ }
// Push the search results
- this.state.searchResponse.match({
- some: res => {
- pushNotNull(
- combined,
- res.comments?.map(e => this.commentViewToCombined(e))
- );
- pushNotNull(
- combined,
- res.posts?.map(e => this.postViewToCombined(e))
- );
- pushNotNull(
- combined,
- res.communities?.map(e => this.communityViewToCombined(e))
- );
- pushNotNull(
- combined,
- res.users?.map(e => this.personViewSafeToCombined(e))
- );
- },
- none: void 0,
- });
+ let searchRes = this.state.searchResponse;
+ if (searchRes) {
+ pushNotNull(
+ combined,
+ searchRes.comments?.map(e => this.commentViewToCombined(e))
+ );
+ pushNotNull(
+ combined,
+ searchRes.posts?.map(e => this.postViewToCombined(e))
+ );
+ pushNotNull(
+ combined,
+ searchRes.communities?.map(e => this.communityViewToCombined(e))
+ );
+ pushNotNull(
+ combined,
+ searchRes.users?.map(e => this.personViewSafeToCombined(e))
+ );
+ }
// Sort it
if (this.state.sort == SortType.New) {
<PostListing
key={(i.data as PostView).post.id}
post_view={i.data as PostView}
- duplicates={None}
- moderators={None}
- admins={None}
showCommunity
enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)}
]}
viewType={CommentViewType.Flat}
viewOnly
- moderators={None}
- admins={None}
- maxCommentsShown={None}
locked
noIndent
enableDownvotes={enableDownvotes(this.state.siteRes)}
comments() {
let comments: CommentView[] = [];
-
- this.state.resolveObjectResponse.match({
- some: res => pushNotNull(comments, res.comment),
- none: void 0,
- });
- this.state.searchResponse.match({
- some: res => pushNotNull(comments, res.comments),
- none: void 0,
- });
+ pushNotNull(comments, this.state.resolveObjectResponse?.comment);
+ pushNotNull(comments, this.state.searchResponse?.comments);
return (
<CommentNodes
viewOnly
locked
noIndent
- moderators={None}
- admins={None}
- maxCommentsShown={None}
enableDownvotes={enableDownvotes(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
siteLanguages={this.state.siteRes.discussion_languages}
posts() {
let posts: PostView[] = [];
- this.state.resolveObjectResponse.match({
- some: res => pushNotNull(posts, res.post),
- none: void 0,
- });
- this.state.searchResponse.match({
- some: res => pushNotNull(posts, res.posts),
- none: void 0,
- });
+ pushNotNull(posts, this.state.resolveObjectResponse?.post);
+ pushNotNull(posts, this.state.searchResponse?.posts);
return (
<>
<PostListing
post_view={pv}
showCommunity
- duplicates={None}
- moderators={None}
- admins={None}
enableDownvotes={enableDownvotes(this.state.siteRes)}
enableNsfw={enableNsfw(this.state.siteRes)}
allLanguages={this.state.siteRes.all_languages}
communities() {
let communities: CommunityView[] = [];
- this.state.resolveObjectResponse.match({
- some: res => pushNotNull(communities, res.community),
- none: void 0,
- });
- this.state.searchResponse.match({
- some: res => pushNotNull(communities, res.communities),
- none: void 0,
- });
+ pushNotNull(communities, this.state.resolveObjectResponse?.community);
+ pushNotNull(communities, this.state.searchResponse?.communities);
return (
<>
users() {
let users: PersonViewSafe[] = [];
- this.state.resolveObjectResponse.match({
- some: res => pushNotNull(users, res.person),
- none: void 0,
- });
- this.state.searchResponse.match({
- some: res => pushNotNull(users, res.users),
- none: void 0,
- });
+ pushNotNull(users, this.state.resolveObjectResponse?.person);
+ pushNotNull(users, this.state.searchResponse?.users);
return (
<>
}
creatorFilter() {
+ let creatorPv = this.state.creatorDetails?.person_view;
return (
<div className="form-group col-sm-6">
<label className="col-form-label" htmlFor="creator-filter">
value={this.state.creatorId}
>
<option value="0">{i18n.t("all")}</option>
- {this.state.creatorDetails.match({
- some: creator => (
- <option value={creator.person_view.person.id}>
- {personSelectName(creator.person_view)}
- </option>
- ),
- none: <></>,
- })}
+ {creatorPv && (
+ <option value={creatorPv.person.id}>
+ {personSelectName(creatorPv)}
+ </option>
+ )}
</select>
</div>
</div>
}
resultsCount(): number {
- let searchCount = this.state.searchResponse
- .map(
- r =>
- r.posts?.length +
- r.comments?.length +
- r.communities?.length +
- r.users?.length
- )
- .unwrapOr(0);
-
- let resObjCount = this.state.resolveObjectResponse
- .map(r => (r.post || r.person || r.community || r.comment ? 1 : 0))
- .unwrapOr(0);
+ let r = this.state.searchResponse;
+
+ let searchCount = r
+ ? r.posts?.length +
+ r.comments?.length +
+ r.communities?.length +
+ r.users?.length
+ : 0;
+
+ let resolveRes = this.state.resolveObjectResponse;
+ let resObjCount = resolveRes
+ ? resolveRes.post ||
+ resolveRes.person ||
+ resolveRes.community ||
+ resolveRes.comment
+ ? 1
+ : 0
+ : 0;
return resObjCount + searchCount;
}
}
search() {
- let community_id: Option<number> =
- this.state.communityId == 0 ? None : Some(this.state.communityId);
- let creator_id: Option<number> =
- this.state.creatorId == 0 ? None : Some(this.state.creatorId);
+ let community_id =
+ this.state.communityId == 0 ? undefined : this.state.communityId;
+ let creator_id =
+ this.state.creatorId == 0 ? undefined : this.state.creatorId;
- let form = new SearchForm({
+ let auth = myAuth(false);
+ let form: SearchForm = {
q: this.state.q,
community_id,
- community_name: None,
creator_id,
- type_: Some(this.state.type_),
- sort: Some(this.state.sort),
- listing_type: Some(this.state.listingType),
- page: Some(this.state.page),
- limit: Some(fetchLimit),
- auth: auth(false).ok(),
- });
+ type_: this.state.type_,
+ sort: this.state.sort,
+ listing_type: this.state.listingType,
+ page: this.state.page,
+ limit: fetchLimit,
+ auth,
+ };
- let resolveObjectForm = new ResolveObject({
+ let resolveObjectForm: ResolveObject = {
q: this.state.q,
- auth: auth(false).ok(),
- });
+ auth,
+ };
if (this.state.q != "") {
this.setState({
- searchResponse: None,
- resolveObjectResponse: None,
+ searchResponse: undefined,
+ resolveObjectResponse: undefined,
loading: true,
});
WebSocketService.Instance.send(wsClient.search(form));
if (msg.error) {
if (msg.error == "couldnt_find_object") {
this.setState({
- resolveObjectResponse: Some({
- comment: None,
- post: None,
- community: None,
- person: None,
- }),
+ resolveObjectResponse: {},
});
this.checkFinishedLoading();
} else {
return;
}
} else if (op == UserOperation.Search) {
- let data = wsJsonToRes<SearchResponse>(msg, SearchResponse);
- this.setState({ searchResponse: Some(data) });
+ let data = wsJsonToRes<SearchResponse>(msg);
+ this.setState({ searchResponse: data });
window.scrollTo(0, 0);
this.checkFinishedLoading();
restoreScrollPosition(this.context);
} else if (op == UserOperation.CreateCommentLike) {
- let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+ let data = wsJsonToRes<CommentResponse>(msg);
createCommentLikeRes(
data.comment_view,
- this.state.searchResponse.map(r => r.comments).unwrapOr([])
+ this.state.searchResponse?.comments
);
this.setState(this.state);
} else if (op == UserOperation.CreatePostLike) {
- let data = wsJsonToRes<PostResponse>(msg, PostResponse);
- createPostLikeFindRes(
- data.post_view,
- this.state.searchResponse.map(r => r.posts).unwrapOr([])
- );
+ let data = wsJsonToRes<PostResponse>(msg);
+ createPostLikeFindRes(data.post_view, this.state.searchResponse?.posts);
this.setState(this.state);
} else if (op == UserOperation.ListCommunities) {
- let data = wsJsonToRes<ListCommunitiesResponse>(
- msg,
- ListCommunitiesResponse
- );
+ let data = wsJsonToRes<ListCommunitiesResponse>(msg);
this.setState({ communities: data.communities });
this.setupCommunityFilter();
} else if (op == UserOperation.ResolveObject) {
- let data = wsJsonToRes<ResolveObjectResponse>(msg, ResolveObjectResponse);
- this.setState({ resolveObjectResponse: Some(data) });
+ let data = wsJsonToRes<ResolveObjectResponse>(msg);
+ this.setState({ resolveObjectResponse: data });
this.checkFinishedLoading();
}
}
checkFinishedLoading() {
- if (
- this.state.searchResponse.isSome() &&
- this.state.resolveObjectResponse.isSome()
- ) {
+ if (this.state.searchResponse && this.state.resolveObjectResponse) {
this.setState({ loading: false });
}
}
-import { Either, Option } from "@sniptt/monads";
import { GetSiteResponse, LemmyHttp } from "lemmy-js-client";
/**
}
export interface InitialFetchRequest {
- auth: Option<string>;
+ auth?: string;
client: LemmyHttp;
path: string;
}
export interface PostFormParams {
- name: Option<string>;
- url: Option<string>;
- body: Option<string>;
- nameOrId: Option<Either<string, number>>;
+ name?: string;
+ url?: string;
+ body?: string;
+ nameOrId?: string | number;
}
export enum CommentViewType {
+import { Inferno } from "inferno";
import { IRouteProps } from "inferno-router/dist/Route";
import { Communities } from "./components/community/communities";
import { Community } from "./components/community/community";
import { InitialFetchRequest } from "./interfaces";
interface IRoutePropsWithFetch extends IRouteProps {
+ // TODO Make sure this one is good.
+ component: Inferno.ComponentClass;
fetchInitialData?(req: InitialFetchRequest): Promise<any>[];
}
// import Cookies from 'js-cookie';
-import { Err, None, Ok, Option, Result, Some } from "@sniptt/monads";
import IsomorphicCookie from "isomorphic-cookie";
import jwt_decode from "jwt-decode";
import { LoginResponse, MyUserInfo } from "lemmy-js-client";
export class UserService {
private static _instance: UserService;
- public myUserInfo: Option<MyUserInfo> = None;
- public jwtInfo: Option<JwtInfo> = None;
+ public myUserInfo?: MyUserInfo;
+ public jwtInfo?: JwtInfo;
public unreadInboxCountSub: BehaviorSubject<number> =
new BehaviorSubject<number>(0);
public unreadReportCountSub: BehaviorSubject<number> =
public login(res: LoginResponse) {
let expires = new Date();
expires.setDate(expires.getDate() + 365);
- res.jwt.match({
- some: jwt => {
- toast(i18n.t("logged_in"));
- IsomorphicCookie.save("jwt", jwt, { expires, secure: isHttps });
- this.setJwtInfo();
- },
- none: void 0,
- });
+ if (res.jwt) {
+ toast(i18n.t("logged_in"));
+ IsomorphicCookie.save("jwt", res.jwt, { expires, secure: isHttps });
+ this.setJwtInfo();
+ }
}
public logout() {
- this.jwtInfo = None;
- this.myUserInfo = None;
+ this.jwtInfo = undefined;
+ this.myUserInfo = undefined;
IsomorphicCookie.remove("jwt"); // TODO is sometimes unreliable for some reason
document.cookie = "jwt=; Max-Age=0; path=/; domain=" + location.hostname;
location.reload();
}
- public auth(throwErr = true): Result<string, string> {
- // Can't use match to convert to result for some reason
- let jwt = this.jwtInfo.map(j => j.jwt);
- if (jwt.isSome()) {
- return Ok(jwt.unwrap());
+ public auth(throwErr = true): string | undefined {
+ let jwt = this.jwtInfo?.jwt;
+ if (jwt) {
+ return jwt;
} else {
let msg = "No JWT cookie found";
if (throwErr && isBrowser()) {
- console.log(msg);
+ console.error(msg);
toast(i18n.t("not_logged_in"), "danger");
}
- return Err(msg);
+ return undefined;
+ // throw msg;
}
}
private setJwtInfo() {
- let jwt = IsomorphicCookie.load("jwt");
+ let jwt: string | undefined = IsomorphicCookie.load("jwt");
if (jwt) {
- let jwtInfo: JwtInfo = { jwt, claims: jwt_decode(jwt) };
- this.jwtInfo = Some(jwtInfo);
+ this.jwtInfo = { jwt, claims: jwt_decode(jwt) };
}
}
-import { Err, None, Ok, Option, Result, Some } from "@sniptt/monads";
-import { ClassConstructor, deserialize, serialize } from "class-transformer";
import emojiShortName from "emoji-short-name";
import {
BlockCommunityResponse,
CommentReportView,
CommentSortType,
CommentView,
- CommunityBlockView,
CommunityModeratorView,
CommunityView,
GetSiteMetadata,
LemmyHttp,
LemmyWebsocket,
ListingType,
- MyUserInfo,
- PersonBlockView,
PersonSafe,
PersonViewSafe,
PostReportView,
Search,
SearchType,
SortType,
- toUndefined,
} from "lemmy-js-client";
import { default as MarkdownIt } from "markdown-it";
import markdown_it_container from "markdown-it-container";
return { __html: md.renderInline(text) };
}
-export function getUnixTime(text: string): number {
+export function getUnixTime(text?: string): number | undefined {
return text ? new Date(text).getTime() / 1000 : undefined;
}
-export function futureDaysToUnixTime(days: number): number {
+export function futureDaysToUnixTime(days?: number): number | undefined {
return days
? Math.trunc(
new Date(Date.now() + 1000 * 60 * 60 * 24 * days).getTime() / 1000
}
export function canMod(
- mods: Option<CommunityModeratorView[]>,
- admins: Option<PersonViewSafe[]>,
creator_id: number,
+ mods?: CommunityModeratorView[],
+ admins?: PersonViewSafe[],
myUserInfo = UserService.Instance.myUserInfo,
onSelf = false
): boolean {
// You can do moderator actions only on the mods added after you.
- let adminsThenMods = admins
- .unwrapOr([])
- .map(a => a.person.id)
- .concat(mods.unwrapOr([]).map(m => m.moderator.id));
-
- return myUserInfo.match({
- some: me => {
- let myIndex = adminsThenMods.findIndex(
- id => id == me.local_user_view.person.id
- );
- if (myIndex == -1) {
- return false;
- } else {
- // onSelf +1 on mod actions not for yourself, IE ban, remove, etc
- adminsThenMods = adminsThenMods.slice(0, myIndex + (onSelf ? 0 : 1));
- return !adminsThenMods.includes(creator_id);
- }
- },
- none: false,
- });
+ let adminsThenMods =
+ admins
+ ?.map(a => a.person.id)
+ .concat(mods?.map(m => m.moderator.id) ?? []) ?? [];
+
+ if (myUserInfo) {
+ let myIndex = adminsThenMods.findIndex(
+ id => id == myUserInfo.local_user_view.person.id
+ );
+ if (myIndex == -1) {
+ return false;
+ } else {
+ // onSelf +1 on mod actions not for yourself, IE ban, remove, etc
+ adminsThenMods = adminsThenMods.slice(0, myIndex + (onSelf ? 0 : 1));
+ return !adminsThenMods.includes(creator_id);
+ }
+ } else {
+ return false;
+ }
}
export function canAdmin(
- admins: Option<PersonViewSafe[]>,
- creator_id: number,
+ creatorId: number,
+ admins?: PersonViewSafe[],
myUserInfo = UserService.Instance.myUserInfo,
onSelf = false
): boolean {
- return canMod(None, admins, creator_id, myUserInfo, onSelf);
+ return canMod(creatorId, undefined, admins, myUserInfo, onSelf);
}
export function isMod(
- mods: Option<CommunityModeratorView[]>,
- creator_id: number
+ creatorId: number,
+ mods?: CommunityModeratorView[]
): boolean {
- return mods.match({
- some: mods => mods.map(m => m.moderator.id).includes(creator_id),
- none: false,
- });
+ return mods?.map(m => m.moderator.id).includes(creatorId) ?? false;
}
export function amMod(
- mods: Option<CommunityModeratorView[]>,
+ mods?: CommunityModeratorView[],
myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return myUserInfo.match({
- some: mui => isMod(mods, mui.local_user_view.person.id),
- none: false,
- });
+ return myUserInfo ? isMod(myUserInfo.local_user_view.person.id, mods) : false;
}
-export function isAdmin(
- admins: Option<PersonViewSafe[]>,
- creator_id: number
-): boolean {
- return admins.match({
- some: admins => admins.map(a => a.person.id).includes(creator_id),
- none: false,
- });
+export function isAdmin(creatorId: number, admins?: PersonViewSafe[]): boolean {
+ return admins?.map(a => a.person.id).includes(creatorId) ?? false;
}
export function amAdmin(myUserInfo = UserService.Instance.myUserInfo): boolean {
- return myUserInfo
- .map(mui => mui.local_user_view.person.admin)
- .unwrapOr(false);
+ return myUserInfo?.local_user_view.person.admin ?? false;
}
export function amCommunityCreator(
- mods: Option<CommunityModeratorView[]>,
creator_id: number,
+ mods?: CommunityModeratorView[],
myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return mods.match({
- some: mods =>
- myUserInfo
- .map(mui => mui.local_user_view.person.id)
- .match({
- some: myId =>
- myId == mods[0].moderator.id &&
- // Don't allow mod actions on yourself
- myId != creator_id,
- none: false,
- }),
- none: false,
- });
+ let myId = myUserInfo?.local_user_view.person.id;
+ // Don't allow mod actions on yourself
+ return myId == mods?.at(0)?.moderator.id && myId != creator_id;
}
export function amSiteCreator(
- admins: Option<PersonViewSafe[]>,
creator_id: number,
+ admins?: PersonViewSafe[],
myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return admins.match({
- some: admins =>
- myUserInfo
- .map(mui => mui.local_user_view.person.id)
- .match({
- some: myId =>
- myId == admins[0].person.id &&
- // Don't allow mod actions on yourself
- myId != creator_id,
- none: false,
- }),
- none: false,
- });
+ let myId = myUserInfo?.local_user_view.person.id;
+ return myId == admins?.at(0)?.person.id && myId != creator_id;
}
export function amTopMod(
- mods: Option<CommunityModeratorView[]>,
+ mods: CommunityModeratorView[],
myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return mods.match({
- some: mods =>
- myUserInfo.match({
- some: mui => mods[0].moderator.id == mui.local_user_view.person.id,
- none: false,
- }),
- none: false,
- });
+ return mods.at(0)?.moderator.id == myUserInfo?.local_user_view.person.id;
}
const imageRegex = /(http)?s?:?(\/\/[^"']*\.(?:jpg|jpeg|gif|png|svg|webp))/;
}
export async function getSiteMetadata(url: string) {
- let form = new GetSiteMetadata({
- url,
- });
+ let form: GetSiteMetadata = { url };
let client = new LemmyHttp(httpBase);
return client.getSiteMetadata(form);
}
override?: string,
myUserInfo = UserService.Instance.myUserInfo
): string[] {
- let myLang = myUserInfo
- .map(m => m.local_user_view.local_user.interface_language)
- .unwrapOr("browser");
- let lang = override || myLang;
+ let myLang = myUserInfo?.local_user_view.local_user.interface_language;
+ let lang = override || myLang || "browser";
if (lang == "browser" && isBrowser()) {
return getBrowserLanguages();
let cssLoc = `/css/themes/${theme}.css`;
loadCss(theme, cssLoc);
- document.getElementById(theme).removeAttribute("disabled");
+ document.getElementById(theme)?.removeAttribute("disabled");
}
export function loadCss(id: string, loc: string) {
}
export function showAvatars(
- myUserInfo: Option<MyUserInfo> = UserService.Instance.myUserInfo
+ myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return myUserInfo
- .map(m => m.local_user_view.local_user.show_avatars)
- .unwrapOr(true);
+ return myUserInfo?.local_user_view.local_user.show_avatars ?? true;
}
export function showScores(
- myUserInfo: Option<MyUserInfo> = UserService.Instance.myUserInfo
+ myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return myUserInfo
- .map(m => m.local_user_view.local_user.show_scores)
- .unwrapOr(true);
+ return myUserInfo?.local_user_view.local_user.show_scores ?? true;
}
export function isCakeDay(published: string): boolean {
interface NotifyInfo {
name: string;
- icon: Option<string>;
+ icon?: string;
link: string;
- body: string;
+ body?: string;
}
export function messageToastify(info: NotifyInfo, router: any) {
let toast = Toastify({
text: `${htmlBody}<br />${info.name}`,
- avatar: toUndefined(info.icon),
+ avatar: info.icon,
backgroundColor: backgroundColor,
className: "text-dark",
close: true,
else {
var notification = new Notification(info.name, {
...{ body: info.body },
- ...(info.icon.isSome() && { icon: info.icon.unwrap() }),
+ ...(info.icon && { icon: info.icon }),
});
notification.onclick = (ev: Event): any => {
defaultListingType: ListingType,
myUserInfo = UserService.Instance.myUserInfo
): ListingType {
+ let myLt = myUserInfo?.local_user_view.local_user.default_listing_type;
return props.match.params.listing_type
? routeListingTypeToEnum(props.match.params.listing_type)
- : myUserInfo.match({
- some: me =>
- Object.values(ListingType)[
- me.local_user_view.local_user.default_listing_type
- ],
- none: defaultListingType,
- });
+ : myLt
+ ? Object.values(ListingType)[myLt]
+ : defaultListingType;
}
export function getListingTypeFromPropsNoDefault(props: any): ListingType {
props: any,
myUserInfo = UserService.Instance.myUserInfo
): SortType {
+ let mySortType = myUserInfo?.local_user_view.local_user.default_sort_type;
return props.match.params.sort
? routeSortTypeToEnum(props.match.params.sort)
- : myUserInfo.match({
- some: mui =>
- Object.values(SortType)[
- mui.local_user_view.local_user.default_sort_type
- ],
- none: SortType.Active,
- });
+ : mySortType
+ ? Object.values(SortType)[mySortType]
+ : SortType.Active;
}
export function getPageFromProps(props: any): number {
: 1;
}
-export function getIdFromProps(props: any): Option<number> {
- let id: string = props.match.params.post_id;
- return id ? Some(Number(id)) : None;
+export function getIdFromProps(props: any): number | undefined {
+ let id = props.match.params.post_id;
+ return id ? Number(id) : undefined;
}
-export function getCommentIdFromProps(props: any): Option<number> {
- let id: string = props.match.params.comment_id;
- return id ? Some(Number(id)) : None;
+export function getCommentIdFromProps(props: any): number | undefined {
+ let id = props.match.params.comment_id;
+ return id ? Number(id) : undefined;
}
export function getUsernameFromProps(props: any): string {
return props.match.params.username;
}
-export function editCommentRes(data: CommentView, comments: CommentView[]) {
- let found = comments.find(c => c.comment.id == data.comment.id);
+export function editCommentRes(data: CommentView, comments?: CommentView[]) {
+ let found = comments?.find(c => c.comment.id == data.comment.id);
if (found) {
found.comment.content = data.comment.content;
found.comment.distinguished = data.comment.distinguished;
}
}
-export function saveCommentRes(data: CommentView, comments: CommentView[]) {
- let found = comments.find(c => c.comment.id == data.comment.id);
+export function saveCommentRes(data: CommentView, comments?: CommentView[]) {
+ let found = comments?.find(c => c.comment.id == data.comment.id);
if (found) {
found.saved = data.saved;
}
}
-// TODO Should only use the return now, no state?
export function updatePersonBlock(
data: BlockPersonResponse,
myUserInfo = UserService.Instance.myUserInfo
-): Option<PersonBlockView[]> {
- return myUserInfo.match({
- some: (mui: MyUserInfo) => {
- if (data.blocked) {
- mui.person_blocks.push({
- person: mui.local_user_view.person,
- target: data.person_view.person,
- });
- toast(`${i18n.t("blocked")} ${data.person_view.person.name}`);
- } else {
- mui.person_blocks = mui.person_blocks.filter(
- i => i.target.id != data.person_view.person.id
- );
- toast(`${i18n.t("unblocked")} ${data.person_view.person.name}`);
- }
- return Some(mui.person_blocks);
- },
- none: None,
- });
+) {
+ let mui = myUserInfo;
+ if (mui) {
+ if (data.blocked) {
+ mui.person_blocks.push({
+ person: mui.local_user_view.person,
+ target: data.person_view.person,
+ });
+ toast(`${i18n.t("blocked")} ${data.person_view.person.name}`);
+ } else {
+ mui.person_blocks = mui.person_blocks.filter(
+ i => i.target.id != data.person_view.person.id
+ );
+ toast(`${i18n.t("unblocked")} ${data.person_view.person.name}`);
+ }
+ }
}
export function updateCommunityBlock(
data: BlockCommunityResponse,
myUserInfo = UserService.Instance.myUserInfo
-): Option<CommunityBlockView[]> {
- return myUserInfo.match({
- some: (mui: MyUserInfo) => {
- if (data.blocked) {
- mui.community_blocks.push({
- person: mui.local_user_view.person,
- community: data.community_view.community,
- });
- toast(`${i18n.t("blocked")} ${data.community_view.community.name}`);
- } else {
- mui.community_blocks = mui.community_blocks.filter(
- i => i.community.id != data.community_view.community.id
- );
- toast(`${i18n.t("unblocked")} ${data.community_view.community.name}`);
- }
- return Some(mui.community_blocks);
- },
- none: None,
- });
+) {
+ let mui = myUserInfo;
+ if (mui) {
+ if (data.blocked) {
+ mui.community_blocks.push({
+ person: mui.local_user_view.person,
+ community: data.community_view.community,
+ });
+ toast(`${i18n.t("blocked")} ${data.community_view.community.name}`);
+ } else {
+ mui.community_blocks = mui.community_blocks.filter(
+ i => i.community.id != data.community_view.community.id
+ );
+ toast(`${i18n.t("unblocked")} ${data.community_view.community.name}`);
+ }
+ }
}
export function createCommentLikeRes(
data: CommentView,
- comments: CommentView[]
+ comments?: CommentView[]
) {
- let found = comments.find(c => c.comment.id === data.comment.id);
+ let found = comments?.find(c => c.comment.id === data.comment.id);
if (found) {
found.counts.score = data.counts.score;
found.counts.upvotes = data.counts.upvotes;
}
}
-export function createPostLikeFindRes(data: PostView, posts: PostView[]) {
- let found = posts.find(p => p.post.id == data.post.id);
+export function createPostLikeFindRes(data: PostView, posts?: PostView[]) {
+ let found = posts?.find(p => p.post.id == data.post.id);
if (found) {
createPostLikeRes(data, found);
}
}
-export function createPostLikeRes(data: PostView, post_view: PostView) {
+export function createPostLikeRes(data: PostView, post_view?: PostView) {
if (post_view) {
post_view.counts.score = data.counts.score;
post_view.counts.upvotes = data.counts.upvotes;
}
}
-export function editPostFindRes(data: PostView, posts: PostView[]) {
- let found = posts.find(p => p.post.id == data.post.id);
+export function editPostFindRes(data: PostView, posts?: PostView[]) {
+ let found = posts?.find(p => p.post.id == data.post.id);
if (found) {
editPostRes(data, found);
}
// TODO possible to make these generic?
export function updatePostReportRes(
data: PostReportView,
- reports: PostReportView[]
+ reports?: PostReportView[]
) {
- let found = reports.find(p => p.post_report.id == data.post_report.id);
+ let found = reports?.find(p => p.post_report.id == data.post_report.id);
if (found) {
found.post_report = data.post_report;
}
export function updateCommentReportRes(
data: CommentReportView,
- reports: CommentReportView[]
+ reports?: CommentReportView[]
) {
- let found = reports.find(c => c.comment_report.id == data.comment_report.id);
+ let found = reports?.find(c => c.comment_report.id == data.comment_report.id);
if (found) {
found.comment_report = data.comment_report;
}
export function updatePrivateMessageReportRes(
data: PrivateMessageReportView,
- reports: PrivateMessageReportView[]
+ reports?: PrivateMessageReportView[]
) {
- let found = reports.find(
+ let found = reports?.find(
c => c.private_message_report.id == data.private_message_report.id
);
if (found) {
export function updateRegistrationApplicationRes(
data: RegistrationApplicationView,
- applications: RegistrationApplicationView[]
+ applications?: RegistrationApplicationView[]
) {
- let found = applications.find(
+ let found = applications?.find(
ra => ra.registration_application.id == data.registration_application.id
);
if (found) {
let map = new Map<number, CommentNodeI>();
let depthOffset = !parentComment
? 0
- : getDepthFromComment(comments[0].comment);
+ : getDepthFromComment(comments[0].comment) ?? 0;
for (let comment_view of comments) {
+ let depthI = getDepthFromComment(comment_view.comment) ?? 0;
+ let depth = depthI ? depthI - depthOffset : 0;
let node: CommentNodeI = {
- comment_view: comment_view,
+ comment_view,
children: [],
- depth: getDepthFromComment(comment_view.comment) - depthOffset,
+ depth,
};
map.set(comment_view.comment.id, { ...node });
}
// if its a parent comment fetch, then push the first comment to the top node.
if (parentComment) {
- tree.push(map.get(comments[0].comment.id));
+ let cNode = map.get(comments[0].comment.id);
+ if (cNode) {
+ tree.push(cNode);
+ }
}
for (let comment_view of comments) {
let child = map.get(comment_view.comment.id);
- let parent_id = getCommentParentId(comment_view.comment);
- parent_id.match({
- some: parentId => {
- let parent = map.get(parentId);
+ if (child) {
+ let parent_id = getCommentParentId(comment_view.comment);
+ if (parent_id) {
+ let parent = map.get(parent_id);
// Necessary because blocked comment might not exist
if (parent) {
parent.children.push(child);
}
- },
- none: () => {
+ } else {
if (!parentComment) {
tree.push(child);
}
- },
- });
+ }
+ }
}
return tree;
}
-export function getCommentParentId(comment: CommentI): Option<number> {
- let split = comment.path.split(".");
+export function getCommentParentId(comment?: CommentI): number | undefined {
+ let split = comment?.path.split(".");
// remove the 0
- split.shift();
+ split?.shift();
- if (split.length > 1) {
- return Some(Number(split[split.length - 2]));
- } else {
- return None;
- }
+ return split && split.length > 1
+ ? Number(split.at(split.length - 2))
+ : undefined;
}
-export function getDepthFromComment(comment: CommentI): number {
- return comment.path.split(".").length - 2;
+export function getDepthFromComment(comment?: CommentI): number | undefined {
+ let len = comment?.path.split(".").length;
+ return len ? len - 2 : undefined;
}
export function insertCommentIntoTree(
depth: 0,
};
- getCommentParentId(cv.comment).match({
- some: parentId => {
- let parentComment = searchCommentTree(tree, parentId);
- parentComment.match({
- some: pComment => {
- node.depth = pComment.depth + 1;
- pComment.children.unshift(node);
- },
- none: void 0,
- });
- },
- none: () => {
- if (!parentComment) {
- tree.unshift(node);
- }
- },
- });
+ let parentId = getCommentParentId(cv.comment);
+ if (parentId) {
+ let parent_comment = searchCommentTree(tree, parentId);
+ if (parent_comment) {
+ node.depth = parent_comment.depth + 1;
+ parent_comment.children.unshift(node);
+ }
+ } else if (!parentComment) {
+ tree.unshift(node);
+ }
}
export function searchCommentTree(
tree: CommentNodeI[],
id: number
-): Option<CommentNodeI> {
+): CommentNodeI | undefined {
for (let node of tree) {
if (node.comment_view.comment.id === id) {
- return Some(node);
+ return node;
}
for (const child of node.children) {
let res = searchCommentTree([child], id);
- if (res.isSome()) {
+ if (res) {
return res;
}
}
}
- return None;
+ return undefined;
}
export const colorList: string[] = [
return typeof window !== "undefined";
}
-export function setIsoData<Type1, Type2, Type3, Type4, Type5>(
- context: any,
- cls1?: ClassConstructor<Type1>,
- cls2?: ClassConstructor<Type2>,
- cls3?: ClassConstructor<Type3>,
- cls4?: ClassConstructor<Type4>,
- cls5?: ClassConstructor<Type5>
-): IsoData {
+export function setIsoData(context: any): IsoData {
// If its the browser, you need to deserialize the data from the window
if (isBrowser()) {
let json = window.isoData;
let routeData = json.routeData;
- let routeDataOut: any[] = [];
-
- // Can't do array looping because of specific type constructor required
- if (routeData[0]) {
- routeDataOut[0] = convertWindowJson(cls1, routeData[0]);
- }
- if (routeData[1]) {
- routeDataOut[1] = convertWindowJson(cls2, routeData[1]);
- }
- if (routeData[2]) {
- routeDataOut[2] = convertWindowJson(cls3, routeData[2]);
- }
- if (routeData[3]) {
- routeDataOut[3] = convertWindowJson(cls4, routeData[3]);
- }
- if (routeData[4]) {
- routeDataOut[4] = convertWindowJson(cls5, routeData[4]);
- }
- let site_res = convertWindowJson(GetSiteResponse, json.site_res);
+ let site_res = json.site_res;
let isoData: IsoData = {
path: json.path,
site_res,
- routeData: routeDataOut,
+ routeData,
};
return isoData;
} else return context.router.staticContext;
}
-/**
- * Necessary since window ISOData can't store function types like Option
- */
-export function convertWindowJson<T>(cls: ClassConstructor<T>, data: any): T {
- return deserialize(cls, serialize(data));
-}
-
-export function wsSubscribe(parseMessage: any): Subscription {
+export function wsSubscribe(parseMessage: any): Subscription | undefined {
if (isBrowser()) {
return WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
() => console.log("complete")
);
} else {
- return null;
+ return undefined;
}
}
}
export function showLocal(isoData: IsoData): boolean {
- return isoData.site_res.federated_instances
- .map(f => f.linked.length > 0)
- .unwrapOr(false);
+ let linked = isoData.site_res.federated_instances?.linked;
+ return linked ? linked.length > 0 : false;
}
export interface ChoicesValue {
}
export async function fetchCommunities(q: string) {
- let form = new Search({
+ let form: Search = {
q,
- type_: Some(SearchType.Communities),
- sort: Some(SortType.TopAll),
- listing_type: Some(ListingType.All),
- page: Some(1),
- limit: Some(fetchLimit),
- community_id: None,
- community_name: None,
- creator_id: None,
- auth: auth(false).ok(),
- });
+ type_: SearchType.Communities,
+ sort: SortType.TopAll,
+ listing_type: ListingType.All,
+ page: 1,
+ limit: fetchLimit,
+ auth: myAuth(false),
+ };
let client = new LemmyHttp(httpBase);
return client.search(form);
}
export async function fetchUsers(q: string) {
- let form = new Search({
+ let form: Search = {
q,
- type_: Some(SearchType.Users),
- sort: Some(SortType.TopAll),
- listing_type: Some(ListingType.All),
- page: Some(1),
- limit: Some(fetchLimit),
- community_id: None,
- community_name: None,
- creator_id: None,
- auth: auth(false).ok(),
- });
+ type_: SearchType.Users,
+ sort: SortType.TopAll,
+ listing_type: ListingType.All,
+ page: 1,
+ limit: fetchLimit,
+ auth: myAuth(false),
+ };
let client = new LemmyHttp(httpBase);
return client.search(form);
}
}
export function personSelectName(pvs: PersonViewSafe): string {
- let pName = pvs.person.display_name.unwrapOr(pvs.person.name);
+ let pName = pvs.person.display_name ?? pvs.person.name;
return pvs.person.local ? pName : `${hostname(pvs.person.actor_id)}/${pName}`;
}
let expires = ps.ban_expires;
// Add Z to convert from UTC date
// TODO this check probably isn't necessary anymore
- if (expires.isSome()) {
- if (ps.banned && new Date(expires.unwrap() + "Z") > new Date()) {
+ if (expires) {
+ if (ps.banned && new Date(expires + "Z") > new Date()) {
return true;
} else {
return false;
}
}
-export function auth(throwErr = true): Result<string, string> {
+export function myAuth(throwErr = true): string | undefined {
return UserService.Instance.auth(throwErr);
}
}
}
-export function arrayGet<T>(arr: Array<T>, index: number): Result<T, string> {
- let out = arr.at(index);
- if (out == undefined) {
- return Err("Index undefined");
- } else {
- return Ok(out);
- }
-}
-
export function myFirstDiscussionLanguageId(
allLanguages: Language[],
siteLanguages: number[],
myUserInfo = UserService.Instance.myUserInfo
-): Option<number> {
- return arrayGet(
- selectableLanguages(allLanguages, siteLanguages, false, false, myUserInfo),
- 0
- )
- .map(l => l.id)
- .ok();
+): number | undefined {
+ return selectableLanguages(
+ allLanguages,
+ siteLanguages,
+ false,
+ false,
+ myUserInfo
+ ).at(0)?.id;
}
export function canCreateCommunity(
pv: PostView,
myUserInfo = UserService.Instance.myUserInfo
): boolean {
- return myUserInfo
- .map(
- mui =>
- mui.community_blocks
- .map(c => c.community.id)
- .includes(pv.community.id) ||
- mui.person_blocks.map(p => p.target.id).includes(pv.creator.id)
- )
- .unwrapOr(false);
+ return (
+ (myUserInfo?.community_blocks
+ .map(c => c.community.id)
+ .includes(pv.community.id) ||
+ myUserInfo?.person_blocks
+ .map(p => p.target.id)
+ .includes(pv.creator.id)) ??
+ false
+ );
}
/// Checks to make sure you can view NSFW posts. Returns true if you can.
myUserInfo = UserService.Instance.myUserInfo
): boolean {
let nsfw = pv.post.nsfw || pv.community.nsfw;
- return (
- !nsfw ||
- (nsfw &&
- myUserInfo
- .map(m => m.local_user_view.local_user.show_nsfw)
- .unwrapOr(false))
- );
+ let myShowNsfw = myUserInfo?.local_user_view.local_user.show_nsfw ?? false;
+ return !nsfw || (nsfw && myShowNsfw);
}
-export function getRandomFromList<T>(list: T[]): T {
- return list[Math.floor(Math.random() * list.length)];
+export function getRandomFromList<T>(list?: T[]): T | undefined {
+ return list?.at(Math.floor(Math.random() * list.length));
}
/**
export function selectableLanguages(
allLanguages: Language[],
siteLanguages: number[],
- showAll: boolean,
- showSite: boolean,
+ showAll?: boolean,
+ showSite?: boolean,
myUserInfo = UserService.Instance.myUserInfo
): Language[] {
let allLangIds = allLanguages.map(l => l.id);
- let myLangs = myUserInfo
- .map(mui => mui.discussion_languages)
- .unwrapOr(allLangIds);
+ let myLangs = myUserInfo?.discussion_languages ?? allLangIds;
myLangs = myLangs.length == 0 ? allLangIds : myLangs;
let siteLangs = siteLanguages.length == 0 ? allLangIds : siteLanguages;
"noUnusedParameters": true,\r
"noImplicitReturns": true,\r
"experimentalDecorators": true,\r
- "strictNullChecks": false,\r
+ "strictNullChecks": true,\r
"noFallthroughCasesInSwitch": true\r
},\r
"include": [\r
domhandler "^4.2.0"
selderee "^0.6.0"
-"@sniptt/monads@^0.5.10":
- version "0.5.10"
- resolved "https://registry.yarnpkg.com/@sniptt/monads/-/monads-0.5.10.tgz#a80cd00738bbd682d36d36dd36bdc0bddc96eb76"
- integrity sha512-+agDOv9DpDV+9e2zN/Vmdk+XaqGx5Sykl0fqhqgiJ90r18nsBkxe44DmZ2sA1HYK+MSsBeZBiAr6pq4w+5uhfw==
-
"@types/autosize@^4.0.0":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/autosize/-/autosize-4.0.1.tgz#999a7c305b96766248044ebaac1a0299961f3b61"
resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-1.0.6.tgz#74abfd619df370b9d54ab14475568e97dd64c0c1"
integrity sha512-vIIQZtDT0y3GmcVqi4Uhd43s7HKn5DtH8/CcmHe/XG1Vb4JpUgOfTynZzYSo1zeB+j4GbA38Eu2P9UTbIzDw5g==
-class-transformer@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336"
- integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==
-
classnames@^2.3.1:
version "2.3.2"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
dependencies:
invert-kv "^1.0.0"
-lemmy-js-client@0.17.0-rc.57:
- version "0.17.0-rc.57"
- resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.57.tgz#f7a243ed53542810e7446b0a28ad162f3e913254"
- integrity sha512-7kZHi0B+jiKc50itTwngkS5Vxcuvux3LjgD28IXZ049cWQgZDqer6BCmudcbViP+dAoyWs9Fh2SyWkYFhv7bwQ==
+lemmy-js-client@0.17.0-rc.61:
+ version "0.17.0-rc.61"
+ resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.61.tgz#c01e129a3d4c3483ecf337f1e4acf0ad91f9684f"
+ integrity sha512-xauBCD5i4vlUEWqsTMIXLCXeIjAK7ivVIN3C/g+RMAM7mD3CTcRkDZUerwnvLipIfr7V/4iYLWZW0orBaiV1CQ==
dependencies:
- "@sniptt/monads" "^0.5.10"
- class-transformer "^0.5.1"
node-fetch "2.6.6"
- reflect-metadata "^0.1.13"
levn@^0.4.1:
version "0.4.1"
dependencies:
"@babel/runtime" "^7.9.2"
-reflect-metadata@^0.1.13:
- version "0.1.13"
- resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
- integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
-
regenerate-unicode-properties@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c"