mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-12-23 03:11:25 +00:00
Private instances (#523)
* Updating translations. * Adding registration applications. * Updating translations. * Adding verify email route. * Fix missing signup question bug. * Updating translations. * A few fixes from comments on lemmy PR. * v0.15.0-rc.4 * Some suggestions from PR. * v0.15.0-rc.5 * Adding optional auth to modlog fetches. * v0.15.0-rc.6 * Hide deny / approve buttons
This commit is contained in:
parent
4c6713d3f2
commit
b96e16b4e9
23 changed files with 849 additions and 65 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit 0412b6b349e5e8d6ac3ed88801187833e95c72c9
|
Subproject commit 1e0bb9920cda13bb128c87e85125b98ab8f319b6
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "lemmy-ui",
|
"name": "lemmy-ui",
|
||||||
"description": "An isomorphic UI for lemmy",
|
"description": "An isomorphic UI for lemmy",
|
||||||
"version": "0.14.5",
|
"version": "0.15.0-rc.6",
|
||||||
"author": "Dessalines <tyhou13@gmx.com>",
|
"author": "Dessalines <tyhou13@gmx.com>",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -72,7 +72,7 @@
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"import-sort-style-module": "^6.0.0",
|
"import-sort-style-module": "^6.0.0",
|
||||||
"iso-639-1": "^2.1.10",
|
"iso-639-1": "^2.1.10",
|
||||||
"lemmy-js-client": "0.14.0-rc.1",
|
"lemmy-js-client": "0.15.0-rc.6",
|
||||||
"lint-staged": "^12.1.2",
|
"lint-staged": "^12.1.2",
|
||||||
"mini-css-extract-plugin": "^2.4.5",
|
"mini-css-extract-plugin": "^2.4.5",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
|
|
@ -91,7 +91,11 @@ server.get("/*", async (req, res) => {
|
||||||
if (routeData[0] && routeData[0].error) {
|
if (routeData[0] && routeData[0].error) {
|
||||||
let errCode = routeData[0].error;
|
let errCode = routeData[0].error;
|
||||||
console.error(errCode);
|
console.error(errCode);
|
||||||
return res.redirect(`/404?err=${errCode}`);
|
if (errCode == "instance_is_private") {
|
||||||
|
return res.redirect(`/signup`);
|
||||||
|
} else {
|
||||||
|
return res.redirect(`/404?err=${errCode}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let isoData: IsoData = {
|
let isoData: IsoData = {
|
||||||
|
|
|
@ -7,6 +7,8 @@ import {
|
||||||
GetSiteResponse,
|
GetSiteResponse,
|
||||||
GetUnreadCount,
|
GetUnreadCount,
|
||||||
GetUnreadCountResponse,
|
GetUnreadCountResponse,
|
||||||
|
GetUnreadRegistrationApplicationCount,
|
||||||
|
GetUnreadRegistrationApplicationCountResponse,
|
||||||
PrivateMessageResponse,
|
PrivateMessageResponse,
|
||||||
UserOperation,
|
UserOperation,
|
||||||
} from "lemmy-js-client";
|
} from "lemmy-js-client";
|
||||||
|
@ -41,6 +43,7 @@ interface NavbarState {
|
||||||
expanded: boolean;
|
expanded: boolean;
|
||||||
unreadInboxCount: number;
|
unreadInboxCount: number;
|
||||||
unreadReportCount: number;
|
unreadReportCount: number;
|
||||||
|
unreadApplicationCount: number;
|
||||||
searchParam: string;
|
searchParam: string;
|
||||||
toggleSearch: boolean;
|
toggleSearch: boolean;
|
||||||
showDropdown: boolean;
|
showDropdown: boolean;
|
||||||
|
@ -52,11 +55,13 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
private userSub: Subscription;
|
private userSub: Subscription;
|
||||||
private unreadInboxCountSub: Subscription;
|
private unreadInboxCountSub: Subscription;
|
||||||
private unreadReportCountSub: Subscription;
|
private unreadReportCountSub: Subscription;
|
||||||
|
private unreadApplicationCountSub: Subscription;
|
||||||
private searchTextField: RefObject<HTMLInputElement>;
|
private searchTextField: RefObject<HTMLInputElement>;
|
||||||
emptyState: NavbarState = {
|
emptyState: NavbarState = {
|
||||||
isLoggedIn: !!this.props.site_res.my_user,
|
isLoggedIn: !!this.props.site_res.my_user,
|
||||||
unreadInboxCount: 0,
|
unreadInboxCount: 0,
|
||||||
unreadReportCount: 0,
|
unreadReportCount: 0,
|
||||||
|
unreadApplicationCount: 0,
|
||||||
expanded: false,
|
expanded: false,
|
||||||
searchParam: "",
|
searchParam: "",
|
||||||
toggleSearch: false,
|
toggleSearch: false,
|
||||||
|
@ -115,6 +120,11 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
UserService.Instance.unreadReportCountSub.subscribe(res => {
|
UserService.Instance.unreadReportCountSub.subscribe(res => {
|
||||||
this.setState({ unreadReportCount: res });
|
this.setState({ unreadReportCount: res });
|
||||||
});
|
});
|
||||||
|
// Subscribe to unread application count
|
||||||
|
this.unreadApplicationCountSub =
|
||||||
|
UserService.Instance.unreadApplicationCountSub.subscribe(res => {
|
||||||
|
this.setState({ unreadApplicationCount: res });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +133,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
this.userSub.unsubscribe();
|
this.userSub.unsubscribe();
|
||||||
this.unreadInboxCountSub.unsubscribe();
|
this.unreadInboxCountSub.unsubscribe();
|
||||||
this.unreadReportCountSub.unsubscribe();
|
this.unreadReportCountSub.unsubscribe();
|
||||||
|
this.unreadApplicationCountSub.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUrl() {
|
updateUrl() {
|
||||||
|
@ -215,6 +226,31 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
{UserService.Instance.myUserInfo?.local_user_view.person
|
||||||
|
.admin && (
|
||||||
|
<ul class="navbar-nav ml-1">
|
||||||
|
<li className="nav-item">
|
||||||
|
<NavLink
|
||||||
|
to="/registration_applications"
|
||||||
|
className="p-1 navbar-toggler nav-link border-0"
|
||||||
|
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
|
||||||
|
title={i18n.t("unread_registration_applications", {
|
||||||
|
count: this.state.unreadApplicationCount,
|
||||||
|
formattedCount: numToSI(
|
||||||
|
this.state.unreadApplicationCount
|
||||||
|
),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Icon icon="clipboard" />
|
||||||
|
{this.state.unreadApplicationCount > 0 && (
|
||||||
|
<span class="mx-1 badge badge-light">
|
||||||
|
{numToSI(this.state.unreadApplicationCount)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
|
@ -366,6 +402,31 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
)}
|
)}
|
||||||
|
{UserService.Instance.myUserInfo?.local_user_view.person
|
||||||
|
.admin && (
|
||||||
|
<ul class="navbar-nav my-2">
|
||||||
|
<li className="nav-item">
|
||||||
|
<NavLink
|
||||||
|
to="/registration_applications"
|
||||||
|
className="nav-link"
|
||||||
|
onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
|
||||||
|
title={i18n.t("unread_registration_applications", {
|
||||||
|
count: this.state.unreadApplicationCount,
|
||||||
|
formattedCount: numToSI(
|
||||||
|
this.state.unreadApplicationCount
|
||||||
|
),
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Icon icon="clipboard" />
|
||||||
|
{this.state.unreadApplicationCount > 0 && (
|
||||||
|
<span class="mx-1 badge badge-light">
|
||||||
|
{numToSI(this.state.unreadApplicationCount)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</NavLink>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
<button
|
<button
|
||||||
|
@ -537,6 +598,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
this.state.unreadReportCount = data.post_reports + data.comment_reports;
|
this.state.unreadReportCount = data.post_reports + data.comment_reports;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
this.sendReportUnread();
|
this.sendReportUnread();
|
||||||
|
} else if (op == UserOperation.GetUnreadRegistrationApplicationCount) {
|
||||||
|
let data =
|
||||||
|
wsJsonToRes<GetUnreadRegistrationApplicationCountResponse>(msg).data;
|
||||||
|
this.state.unreadApplicationCount = data.registration_applications;
|
||||||
|
this.setState(this.state);
|
||||||
|
this.sendApplicationUnread();
|
||||||
} else if (op == UserOperation.GetSite) {
|
} else if (op == UserOperation.GetSite) {
|
||||||
// This is only called on a successful login
|
// This is only called on a successful login
|
||||||
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
let data = wsJsonToRes<GetSiteResponse>(msg).data;
|
||||||
|
@ -586,7 +653,6 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
let unreadForm: GetUnreadCount = {
|
let unreadForm: GetUnreadCount = {
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
};
|
};
|
||||||
|
|
||||||
WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm));
|
WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm));
|
||||||
|
|
||||||
console.log("Fetching reports...");
|
console.log("Fetching reports...");
|
||||||
|
@ -594,8 +660,18 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
let reportCountForm: GetReportCount = {
|
let reportCountForm: GetReportCount = {
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
};
|
};
|
||||||
|
|
||||||
WebSocketService.Instance.send(wsClient.getReportCount(reportCountForm));
|
WebSocketService.Instance.send(wsClient.getReportCount(reportCountForm));
|
||||||
|
|
||||||
|
if (UserService.Instance.myUserInfo?.local_user_view.person.admin) {
|
||||||
|
console.log("Fetching applications...");
|
||||||
|
|
||||||
|
let applicationCountForm: GetUnreadRegistrationApplicationCount = {
|
||||||
|
auth: authField(),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(
|
||||||
|
wsClient.getUnreadRegistrationApplicationCount(applicationCountForm)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get currentLocation() {
|
get currentLocation() {
|
||||||
|
@ -612,6 +688,12 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendApplicationUnread() {
|
||||||
|
UserService.Instance.unreadApplicationCountSub.next(
|
||||||
|
this.state.unreadApplicationCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
get canAdmin(): boolean {
|
get canAdmin(): boolean {
|
||||||
return (
|
return (
|
||||||
UserService.Instance.myUserInfo &&
|
UserService.Instance.myUserInfo &&
|
||||||
|
|
|
@ -25,6 +25,9 @@ export class CommentReport extends Component<CommentReportProps, any> {
|
||||||
render() {
|
render() {
|
||||||
let r = this.props.report;
|
let r = this.props.report;
|
||||||
let comment = r.comment;
|
let comment = r.comment;
|
||||||
|
let tippyContent = i18n.t(
|
||||||
|
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
|
||||||
|
);
|
||||||
|
|
||||||
// Set the original post data ( a troll could change it )
|
// Set the original post data ( a troll could change it )
|
||||||
comment.content = r.comment_report.original_comment_text;
|
comment.content = r.comment_report.original_comment_text;
|
||||||
|
@ -78,12 +81,8 @@ export class CommentReport extends Component<CommentReportProps, any> {
|
||||||
<button
|
<button
|
||||||
className="btn btn-link btn-animate text-muted py-0"
|
className="btn btn-link btn-animate text-muted py-0"
|
||||||
onClick={linkEvent(this, this.handleResolveReport)}
|
onClick={linkEvent(this, this.handleResolveReport)}
|
||||||
data-tippy-content={
|
data-tippy-content={tippyContent}
|
||||||
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
|
aria-label={tippyContent}
|
||||||
}
|
|
||||||
aria-label={
|
|
||||||
r.comment_report.resolved ? "unresolve_report" : "resolve_report"
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon="check"
|
icon="check"
|
|
@ -17,7 +17,7 @@ import {
|
||||||
import { Icon, Spinner } from "./icon";
|
import { Icon, Spinner } from "./icon";
|
||||||
|
|
||||||
interface MarkdownTextAreaProps {
|
interface MarkdownTextAreaProps {
|
||||||
initialContent: string;
|
initialContent?: string;
|
||||||
finished?: boolean;
|
finished?: boolean;
|
||||||
buttonTitle?: string;
|
buttonTitle?: string;
|
||||||
replyType?: boolean;
|
replyType?: boolean;
|
||||||
|
|
150
src/shared/components/common/registration-application.tsx
Normal file
150
src/shared/components/common/registration-application.tsx
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
import { Component, linkEvent } from "inferno";
|
||||||
|
import { T } from "inferno-i18next-dess";
|
||||||
|
import {
|
||||||
|
ApproveRegistrationApplication,
|
||||||
|
RegistrationApplicationView,
|
||||||
|
} from "lemmy-js-client";
|
||||||
|
import { i18n } from "../../i18next";
|
||||||
|
import { WebSocketService } from "../../services";
|
||||||
|
import { authField, mdToHtml, wsClient } from "../../utils";
|
||||||
|
import { PersonListing } from "../person/person-listing";
|
||||||
|
import { MarkdownTextArea } from "./markdown-textarea";
|
||||||
|
import { MomentTime } from "./moment-time";
|
||||||
|
|
||||||
|
interface RegistrationApplicationProps {
|
||||||
|
application: RegistrationApplicationView;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegistrationApplicationState {
|
||||||
|
denyReason?: string;
|
||||||
|
denyExpanded: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RegistrationApplication extends Component<
|
||||||
|
RegistrationApplicationProps,
|
||||||
|
RegistrationApplicationState
|
||||||
|
> {
|
||||||
|
private emptyState: 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let a = this.props.application;
|
||||||
|
let ra = this.props.application.registration_application;
|
||||||
|
let accepted = a.creator_local_user.accepted_application;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{i18n.t("applicant")}: <PersonListing person={a.creator} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{i18n.t("created")}: <MomentTime showAgo data={ra} />
|
||||||
|
</div>
|
||||||
|
<div>{i18n.t("answer")}:</div>
|
||||||
|
<div className="md-div" dangerouslySetInnerHTML={mdToHtml(ra.answer)} />
|
||||||
|
|
||||||
|
{a.admin && (
|
||||||
|
<div>
|
||||||
|
{accepted ? (
|
||||||
|
<T i18nKey="approved_by">
|
||||||
|
#
|
||||||
|
<PersonListing person={a.admin} />
|
||||||
|
</T>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<T i18nKey="denied_by">
|
||||||
|
#
|
||||||
|
<PersonListing person={a.admin} />
|
||||||
|
</T>
|
||||||
|
<div>
|
||||||
|
{i18n.t("deny_reason")}:{" "}
|
||||||
|
<div
|
||||||
|
className="md-div d-inline-flex"
|
||||||
|
dangerouslySetInnerHTML={mdToHtml(ra.deny_reason || "")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.denyExpanded && (
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-2 col-form-label">
|
||||||
|
{i18n.t("deny_reason")}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<MarkdownTextArea
|
||||||
|
initialContent={this.state.denyReason}
|
||||||
|
onContentChange={this.handleDenyReasonChange}
|
||||||
|
hideNavigationWarnings
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{(!ra.admin_id || (ra.admin_id && !accepted)) && (
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary mr-2 my-2"
|
||||||
|
onClick={linkEvent(this, this.handleApprove)}
|
||||||
|
aria-label={i18n.t("approve")}
|
||||||
|
>
|
||||||
|
{i18n.t("approve")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{(!ra.admin_id || (ra.admin_id && accepted)) && (
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary mr-2"
|
||||||
|
onClick={linkEvent(this, this.handleDeny)}
|
||||||
|
aria-label={i18n.t("deny")}
|
||||||
|
>
|
||||||
|
{i18n.t("deny")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleApprove(i: RegistrationApplication) {
|
||||||
|
i.setState({ denyExpanded: false });
|
||||||
|
let form: ApproveRegistrationApplication = {
|
||||||
|
id: i.props.application.registration_application.id,
|
||||||
|
deny_reason: "",
|
||||||
|
approve: true,
|
||||||
|
auth: authField(),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(
|
||||||
|
wsClient.approveRegistrationApplication(form)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDeny(i: RegistrationApplication) {
|
||||||
|
if (i.state.denyExpanded) {
|
||||||
|
i.setState({ denyExpanded: false });
|
||||||
|
let form: ApproveRegistrationApplication = {
|
||||||
|
id: i.props.application.registration_application.id,
|
||||||
|
approve: false,
|
||||||
|
deny_reason: i.state.denyReason,
|
||||||
|
auth: authField(),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(
|
||||||
|
wsClient.approveRegistrationApplication(form)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
i.setState({ denyExpanded: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDenyReasonChange(val: string) {
|
||||||
|
this.state.denyReason = val;
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,9 @@ export const SYMBOLS = (
|
||||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||||
>
|
>
|
||||||
<defs>
|
<defs>
|
||||||
|
<symbol id="icon-clipboard" viewBox="0 0 24 24">
|
||||||
|
<path d="M7 5c0 0.552 0.225 1.053 0.586 1.414s0.862 0.586 1.414 0.586h6c0.552 0 1.053-0.225 1.414-0.586s0.586-0.862 0.586-1.414h1c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v14c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-12c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM9 1c-0.552 0-1.053 0.225-1.414 0.586s-0.586 0.862-0.586 1.414h-1c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h12c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-14c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-1c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586zM9 3h6v2h-6z"></path>
|
||||||
|
</symbol>
|
||||||
<symbol id="icon-shield" viewBox="0 0 24 24">
|
<symbol id="icon-shield" viewBox="0 0 24 24">
|
||||||
<path d="M12 20.862c-1.184-0.672-4.42-2.695-6.050-5.549-0.079-0.138-0.153-0.276-0.223-0.417-0.456-0.911-0.727-1.878-0.727-2.896v-6.307l7-2.625 7 2.625v6.307c0 1.018-0.271 1.985-0.726 2.897-0.070 0.14-0.145 0.279-0.223 0.417-1.631 2.854-4.867 4.876-6.050 5.549zM12.447 22.894c0 0 4.989-2.475 7.34-6.589 0.096-0.168 0.188-0.34 0.276-0.515 0.568-1.135 0.937-2.408 0.937-3.79v-7c0-0.426-0.267-0.79-0.649-0.936l-8-3c-0.236-0.089-0.485-0.082-0.702 0l-8 3c-0.399 0.149-0.646 0.527-0.649 0.936v7c0 1.382 0.369 2.655 0.938 3.791 0.087 0.175 0.179 0.346 0.276 0.515 2.351 4.114 7.34 6.589 7.34 6.589 0.292 0.146 0.62 0.136 0.894 0z"></path>
|
<path d="M12 20.862c-1.184-0.672-4.42-2.695-6.050-5.549-0.079-0.138-0.153-0.276-0.223-0.417-0.456-0.911-0.727-1.878-0.727-2.896v-6.307l7-2.625 7 2.625v6.307c0 1.018-0.271 1.985-0.726 2.897-0.070 0.14-0.145 0.279-0.223 0.417-1.631 2.854-4.867 4.876-6.050 5.549zM12.447 22.894c0 0 4.989-2.475 7.34-6.589 0.096-0.168 0.188-0.34 0.276-0.515 0.568-1.135 0.937-2.408 0.937-3.79v-7c0-0.426-0.267-0.79-0.649-0.936l-8-3c-0.236-0.089-0.485-0.082-0.702 0l-8 3c-0.399 0.149-0.646 0.527-0.649 0.936v7c0 1.382 0.369 2.655 0.938 3.791 0.087 0.175 0.179 0.346 0.276 0.515 2.351 4.114 7.34 6.589 7.34 6.589 0.292 0.146 0.62 0.136 0.894 0z"></path>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
|
@ -239,6 +239,7 @@ export class Home extends Component<any, HomeState> {
|
||||||
sort: SortType.Hot,
|
sort: SortType.Hot,
|
||||||
limit: 6,
|
limit: 6,
|
||||||
};
|
};
|
||||||
|
setOptionalAuth(trendingCommunitiesForm, req.auth);
|
||||||
promises.push(req.client.listCommunities(trendingCommunitiesForm));
|
promises.push(req.client.listCommunities(trendingCommunitiesForm));
|
||||||
|
|
||||||
return promises;
|
return promises;
|
||||||
|
|
|
@ -185,8 +185,6 @@ export class Login extends Component<any, State> {
|
||||||
if (msg.error) {
|
if (msg.error) {
|
||||||
toast(i18n.t(msg.error), "danger");
|
toast(i18n.t(msg.error), "danger");
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
// Refetch another captcha
|
|
||||||
WebSocketService.Instance.send(wsClient.getCaptcha());
|
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {
|
||||||
authField,
|
authField,
|
||||||
isBrowser,
|
isBrowser,
|
||||||
joinLemmyUrl,
|
joinLemmyUrl,
|
||||||
|
mdToHtml,
|
||||||
setIsoData,
|
setIsoData,
|
||||||
toast,
|
toast,
|
||||||
validEmail,
|
validEmail,
|
||||||
|
@ -27,6 +28,7 @@ import {
|
||||||
} from "../../utils";
|
} from "../../utils";
|
||||||
import { HtmlTags } from "../common/html-tags";
|
import { HtmlTags } from "../common/html-tags";
|
||||||
import { Icon, Spinner } from "../common/icon";
|
import { Icon, Spinner } from "../common/icon";
|
||||||
|
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||||
|
|
||||||
const passwordStrengthOptions: Options<string> = [
|
const passwordStrengthOptions: Options<string> = [
|
||||||
{
|
{
|
||||||
|
@ -77,6 +79,7 @@ export class Signup extends Component<any, State> {
|
||||||
captcha_uuid: undefined,
|
captcha_uuid: undefined,
|
||||||
captcha_answer: undefined,
|
captcha_answer: undefined,
|
||||||
honeypot: undefined,
|
honeypot: undefined,
|
||||||
|
answer: undefined,
|
||||||
},
|
},
|
||||||
registerLoading: false,
|
registerLoading: false,
|
||||||
captcha: undefined,
|
captcha: undefined,
|
||||||
|
@ -88,6 +91,7 @@ export class Signup extends Component<any, State> {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
|
this.handleAnswerChange = this.handleAnswerChange.bind(this);
|
||||||
|
|
||||||
this.parseMessage = this.parseMessage.bind(this);
|
this.parseMessage = this.parseMessage.bind(this);
|
||||||
this.subscription = wsSubscribe(this.parseMessage);
|
this.subscription = wsSubscribe(this.parseMessage);
|
||||||
|
@ -104,7 +108,13 @@ export class Signup extends Component<any, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
get documentTitle(): string {
|
get documentTitle(): string {
|
||||||
return `${i18n.t("login")} - ${this.state.site_view.site.name}`;
|
return `${this.titleName} - ${this.state.site_view.site.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get titleName(): string {
|
||||||
|
return `${i18n.t(
|
||||||
|
this.state.site_view.site.private_instance ? "apply_to_join" : "sign_up"
|
||||||
|
)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isLemmyMl(): boolean {
|
get isLemmyMl(): boolean {
|
||||||
|
@ -128,7 +138,7 @@ export class Signup extends Component<any, State> {
|
||||||
registerForm() {
|
registerForm() {
|
||||||
return (
|
return (
|
||||||
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
|
<form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
|
||||||
<h5>{i18n.t("sign_up")}</h5>
|
<h5>{this.titleName}</h5>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-2 col-form-label" htmlFor="register-username">
|
<label class="col-sm-2 col-form-label" htmlFor="register-username">
|
||||||
|
@ -159,18 +169,24 @@ export class Signup extends Component<any, State> {
|
||||||
type="email"
|
type="email"
|
||||||
id="register-email"
|
id="register-email"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
placeholder={i18n.t("optional")}
|
placeholder={
|
||||||
|
this.state.site_view.site.require_email_verification
|
||||||
|
? i18n.t("required")
|
||||||
|
: i18n.t("optional")
|
||||||
|
}
|
||||||
value={this.state.registerForm.email}
|
value={this.state.registerForm.email}
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
onInput={linkEvent(this, this.handleRegisterEmailChange)}
|
onInput={linkEvent(this, this.handleRegisterEmailChange)}
|
||||||
|
required={this.state.site_view.site.require_email_verification}
|
||||||
minLength={3}
|
minLength={3}
|
||||||
/>
|
/>
|
||||||
{!validEmail(this.state.registerForm.email) && (
|
{!this.state.site_view.site.require_email_verification &&
|
||||||
<div class="mt-2 mb-0 alert alert-light" role="alert">
|
!validEmail(this.state.registerForm.email) && (
|
||||||
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
|
<div class="mt-2 mb-0 alert alert-light" role="alert">
|
||||||
{i18n.t("no_password_reset")}
|
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
|
||||||
</div>
|
{i18n.t("no_password_reset")}
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -219,6 +235,40 @@ export class Signup extends Component<any, State> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{this.state.site_view.site.require_application && (
|
||||||
|
<>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="offset-sm-2 col-sm-10">
|
||||||
|
<div class="mt-2 alert alert-light" role="alert">
|
||||||
|
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
|
||||||
|
{i18n.t("fill_out_application")}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="md-div"
|
||||||
|
dangerouslySetInnerHTML={mdToHtml(
|
||||||
|
this.state.site_view.site.application_question || ""
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<label
|
||||||
|
class="col-sm-2 col-form-label"
|
||||||
|
htmlFor="application_answer"
|
||||||
|
>
|
||||||
|
{i18n.t("answer")}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<MarkdownTextArea
|
||||||
|
onContentChange={this.handleAnswerChange}
|
||||||
|
hideNavigationWarnings
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{this.state.captcha && (
|
{this.state.captcha && (
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-sm-2" htmlFor="register-captcha">
|
<label class="col-sm-2" htmlFor="register-captcha">
|
||||||
|
@ -286,7 +336,7 @@ export class Signup extends Component<any, State> {
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button type="submit" class="btn btn-secondary">
|
<button type="submit" class="btn btn-secondary">
|
||||||
{this.state.registerLoading ? <Spinner /> : i18n.t("sign_up")}
|
{this.state.registerLoading ? <Spinner /> : this.titleName}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -382,6 +432,11 @@ export class Signup extends Component<any, State> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleAnswerChange(val: string) {
|
||||||
|
this.state.registerForm.answer = val;
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
handleHoneyPotChange(i: Signup, event: any) {
|
handleHoneyPotChange(i: Signup, event: any) {
|
||||||
i.state.registerForm.honeypot = event.target.value;
|
i.state.registerForm.honeypot = event.target.value;
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
|
@ -434,13 +489,24 @@ export class Signup extends Component<any, State> {
|
||||||
let data = wsJsonToRes<LoginResponse>(msg).data;
|
let data = wsJsonToRes<LoginResponse>(msg).data;
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
UserService.Instance.login(data);
|
// Only log them in if a jwt was set
|
||||||
WebSocketService.Instance.send(
|
if (data.jwt) {
|
||||||
wsClient.userJoin({
|
UserService.Instance.login(data);
|
||||||
auth: authField(),
|
WebSocketService.Instance.send(
|
||||||
})
|
wsClient.userJoin({
|
||||||
);
|
auth: authField(),
|
||||||
this.props.history.push("/communities");
|
})
|
||||||
|
);
|
||||||
|
this.props.history.push("/communities");
|
||||||
|
} else {
|
||||||
|
if (data.verify_email_sent) {
|
||||||
|
toast(i18n.t("verify_email_sent"));
|
||||||
|
}
|
||||||
|
if (data.registration_created) {
|
||||||
|
toast(i18n.t("registration_application_sent"));
|
||||||
|
}
|
||||||
|
this.props.history.push("/");
|
||||||
|
}
|
||||||
} else if (op == UserOperation.GetCaptcha) {
|
} else if (op == UserOperation.GetCaptcha) {
|
||||||
let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
|
let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
|
||||||
if (data.ok) {
|
if (data.ok) {
|
||||||
|
|
|
@ -3,12 +3,7 @@ import { Prompt } from "inferno-router";
|
||||||
import { CreateSite, EditSite, Site } from "lemmy-js-client";
|
import { CreateSite, EditSite, Site } from "lemmy-js-client";
|
||||||
import { i18n } from "../../i18next";
|
import { i18n } from "../../i18next";
|
||||||
import { WebSocketService } from "../../services";
|
import { WebSocketService } from "../../services";
|
||||||
import {
|
import { authField, capitalizeFirstLetter, wsClient } from "../../utils";
|
||||||
authField,
|
|
||||||
capitalizeFirstLetter,
|
|
||||||
randomStr,
|
|
||||||
wsClient,
|
|
||||||
} from "../../utils";
|
|
||||||
import { Spinner } from "../common/icon";
|
import { Spinner } from "../common/icon";
|
||||||
import { ImageUploadForm } from "../common/image-upload-form";
|
import { ImageUploadForm } from "../common/image-upload-form";
|
||||||
import { MarkdownTextArea } from "../common/markdown-textarea";
|
import { MarkdownTextArea } from "../common/markdown-textarea";
|
||||||
|
@ -24,7 +19,6 @@ interface SiteFormState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
private id = `site-form-${randomStr()}`;
|
|
||||||
private emptyState: SiteFormState = {
|
private emptyState: SiteFormState = {
|
||||||
siteForm: {
|
siteForm: {
|
||||||
enable_downvotes: true,
|
enable_downvotes: true,
|
||||||
|
@ -33,6 +27,10 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
name: null,
|
name: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
banner: null,
|
banner: null,
|
||||||
|
require_email_verification: null,
|
||||||
|
require_application: null,
|
||||||
|
application_question: null,
|
||||||
|
private_instance: null,
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -43,6 +41,8 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
|
this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
|
||||||
|
this.handleSiteApplicationQuestionChange =
|
||||||
|
this.handleSiteApplicationQuestionChange.bind(this);
|
||||||
|
|
||||||
this.handleIconUpload = this.handleIconUpload.bind(this);
|
this.handleIconUpload = this.handleIconUpload.bind(this);
|
||||||
this.handleIconRemove = this.handleIconRemove.bind(this);
|
this.handleIconRemove = this.handleIconRemove.bind(this);
|
||||||
|
@ -51,17 +51,21 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
this.handleBannerRemove = this.handleBannerRemove.bind(this);
|
this.handleBannerRemove = this.handleBannerRemove.bind(this);
|
||||||
|
|
||||||
if (this.props.site) {
|
if (this.props.site) {
|
||||||
|
let site = this.props.site;
|
||||||
this.state.siteForm = {
|
this.state.siteForm = {
|
||||||
name: this.props.site.name,
|
name: site.name,
|
||||||
sidebar: this.props.site.sidebar,
|
sidebar: site.sidebar,
|
||||||
description: this.props.site.description,
|
description: site.description,
|
||||||
enable_downvotes: this.props.site.enable_downvotes,
|
enable_downvotes: site.enable_downvotes,
|
||||||
open_registration: this.props.site.open_registration,
|
open_registration: site.open_registration,
|
||||||
enable_nsfw: this.props.site.enable_nsfw,
|
enable_nsfw: site.enable_nsfw,
|
||||||
community_creation_admin_only:
|
community_creation_admin_only: site.community_creation_admin_only,
|
||||||
this.props.site.community_creation_admin_only,
|
icon: site.icon,
|
||||||
icon: this.props.site.icon,
|
banner: site.banner,
|
||||||
banner: this.props.site.banner,
|
require_email_verification: site.require_email_verification,
|
||||||
|
require_application: site.require_application,
|
||||||
|
application_question: site.application_question,
|
||||||
|
private_instance: site.private_instance,
|
||||||
auth: authField(),
|
auth: authField(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -79,6 +83,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
!this.props.site &&
|
!this.props.site &&
|
||||||
(this.state.siteForm.name ||
|
(this.state.siteForm.name ||
|
||||||
this.state.siteForm.sidebar ||
|
this.state.siteForm.sidebar ||
|
||||||
|
this.state.siteForm.application_question ||
|
||||||
this.state.siteForm.description)
|
this.state.siteForm.description)
|
||||||
) {
|
) {
|
||||||
window.onbeforeunload = () => true;
|
window.onbeforeunload = () => true;
|
||||||
|
@ -100,6 +105,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
!this.props.site &&
|
!this.props.site &&
|
||||||
(this.state.siteForm.name ||
|
(this.state.siteForm.name ||
|
||||||
this.state.siteForm.sidebar ||
|
this.state.siteForm.sidebar ||
|
||||||
|
this.state.siteForm.application_question ||
|
||||||
this.state.siteForm.description)
|
this.state.siteForm.description)
|
||||||
}
|
}
|
||||||
message={i18n.t("block_leaving")}
|
message={i18n.t("block_leaving")}
|
||||||
|
@ -162,9 +168,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label class="col-12 col-form-label" htmlFor={this.id}>
|
<label class="col-12 col-form-label">{i18n.t("sidebar")}</label>
|
||||||
{i18n.t("sidebar")}
|
|
||||||
</label>
|
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<MarkdownTextArea
|
<MarkdownTextArea
|
||||||
initialContent={this.state.siteForm.sidebar}
|
initialContent={this.state.siteForm.sidebar}
|
||||||
|
@ -173,6 +177,20 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{this.state.siteForm.require_application && (
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-12 col-form-label">
|
||||||
|
{i18n.t("application_questionnaire")}
|
||||||
|
</label>
|
||||||
|
<div class="col-12">
|
||||||
|
<MarkdownTextArea
|
||||||
|
initialContent={this.state.siteForm.application_question}
|
||||||
|
onContentChange={this.handleSiteApplicationQuestionChange}
|
||||||
|
hideNavigationWarnings
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
|
@ -255,6 +273,66 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
id="create-site-require-email-verification"
|
||||||
|
type="checkbox"
|
||||||
|
checked={this.state.siteForm.require_email_verification}
|
||||||
|
onChange={linkEvent(
|
||||||
|
this,
|
||||||
|
this.handleSiteRequireEmailVerification
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="form-check-label"
|
||||||
|
htmlFor="create-site-require-email-verification"
|
||||||
|
>
|
||||||
|
{i18n.t("require_email_verification")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
id="create-site-require-application"
|
||||||
|
type="checkbox"
|
||||||
|
checked={this.state.siteForm.require_application}
|
||||||
|
onChange={linkEvent(this, this.handleSiteRequireApplication)}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="form-check-label"
|
||||||
|
htmlFor="create-site-require-application"
|
||||||
|
>
|
||||||
|
{i18n.t("require_registration_application")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
id="create-site-private-instance"
|
||||||
|
type="checkbox"
|
||||||
|
checked={this.state.siteForm.private_instance}
|
||||||
|
onChange={linkEvent(this, this.handleSitePrivateInstance)}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
class="form-check-label"
|
||||||
|
htmlFor="create-site-private-instance"
|
||||||
|
>
|
||||||
|
{i18n.t("private_instance")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<button
|
<button
|
||||||
|
@ -311,6 +389,11 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSiteApplicationQuestionChange(val: string) {
|
||||||
|
this.state.siteForm.application_question = val;
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
handleSiteDescChange(i: SiteForm, event: any) {
|
handleSiteDescChange(i: SiteForm, event: any) {
|
||||||
i.state.siteForm.description = event.target.value;
|
i.state.siteForm.description = event.target.value;
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
|
@ -336,6 +419,21 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSiteRequireApplication(i: SiteForm, event: any) {
|
||||||
|
i.state.siteForm.require_application = event.target.checked;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSiteRequireEmailVerification(i: SiteForm, event: any) {
|
||||||
|
i.state.siteForm.require_email_verification = event.target.checked;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSitePrivateInstance(i: SiteForm, event: any) {
|
||||||
|
i.state.siteForm.private_instance = event.target.checked;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
handleCancel(i: SiteForm) {
|
handleCancel(i: SiteForm) {
|
||||||
i.props.onCancel();
|
i.props.onCancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,11 @@ import { i18n } from "../i18next";
|
||||||
import { InitialFetchRequest } from "../interfaces";
|
import { InitialFetchRequest } from "../interfaces";
|
||||||
import { UserService, WebSocketService } from "../services";
|
import { UserService, WebSocketService } from "../services";
|
||||||
import {
|
import {
|
||||||
|
authField,
|
||||||
fetchLimit,
|
fetchLimit,
|
||||||
isBrowser,
|
isBrowser,
|
||||||
setIsoData,
|
setIsoData,
|
||||||
|
setOptionalAuth,
|
||||||
toast,
|
toast,
|
||||||
wsClient,
|
wsClient,
|
||||||
wsJsonToRes,
|
wsJsonToRes,
|
||||||
|
@ -482,6 +484,7 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
community_id: this.state.communityId,
|
community_id: this.state.communityId,
|
||||||
page: this.state.page,
|
page: this.state.page,
|
||||||
limit: fetchLimit,
|
limit: fetchLimit,
|
||||||
|
auth: authField(false),
|
||||||
};
|
};
|
||||||
WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
|
WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
|
||||||
|
|
||||||
|
@ -507,6 +510,7 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
if (communityId) {
|
if (communityId) {
|
||||||
modlogForm.community_id = Number(communityId);
|
modlogForm.community_id = Number(communityId);
|
||||||
}
|
}
|
||||||
|
setOptionalAuth(modlogForm, req.auth);
|
||||||
|
|
||||||
promises.push(req.client.getModlog(modlogForm));
|
promises.push(req.client.getModlog(modlogForm));
|
||||||
|
|
||||||
|
@ -514,6 +518,7 @@ export class Modlog extends Component<any, ModlogState> {
|
||||||
let communityForm: GetCommunity = {
|
let communityForm: GetCommunity = {
|
||||||
id: Number(communityId),
|
id: Number(communityId),
|
||||||
};
|
};
|
||||||
|
setOptionalAuth(communityForm, req.auth);
|
||||||
promises.push(req.client.getCommunity(communityForm));
|
promises.push(req.client.getCommunity(communityForm));
|
||||||
}
|
}
|
||||||
return promises;
|
return promises;
|
||||||
|
|
249
src/shared/components/person/registration-applications.tsx
Normal file
249
src/shared/components/person/registration-applications.tsx
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
import { Component, linkEvent } from "inferno";
|
||||||
|
import {
|
||||||
|
ListRegistrationApplications,
|
||||||
|
ListRegistrationApplicationsResponse,
|
||||||
|
RegistrationApplicationResponse,
|
||||||
|
RegistrationApplicationView,
|
||||||
|
SiteView,
|
||||||
|
UserOperation,
|
||||||
|
} from "lemmy-js-client";
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
|
import { i18n } from "../../i18next";
|
||||||
|
import { InitialFetchRequest } from "../../interfaces";
|
||||||
|
import { UserService, WebSocketService } from "../../services";
|
||||||
|
import {
|
||||||
|
authField,
|
||||||
|
fetchLimit,
|
||||||
|
isBrowser,
|
||||||
|
setIsoData,
|
||||||
|
setupTippy,
|
||||||
|
toast,
|
||||||
|
updateRegistrationApplicationRes,
|
||||||
|
wsClient,
|
||||||
|
wsJsonToRes,
|
||||||
|
wsSubscribe,
|
||||||
|
wsUserOp,
|
||||||
|
} from "../../utils";
|
||||||
|
import { HtmlTags } from "../common/html-tags";
|
||||||
|
import { Spinner } from "../common/icon";
|
||||||
|
import { Paginator } from "../common/paginator";
|
||||||
|
import { RegistrationApplication } from "../common/registration-application";
|
||||||
|
|
||||||
|
enum UnreadOrAll {
|
||||||
|
Unread,
|
||||||
|
All,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RegistrationApplicationsState {
|
||||||
|
applications: RegistrationApplicationView[];
|
||||||
|
page: number;
|
||||||
|
site_view: SiteView;
|
||||||
|
unreadOrAll: UnreadOrAll;
|
||||||
|
loading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RegistrationApplications extends Component<
|
||||||
|
any,
|
||||||
|
RegistrationApplicationsState
|
||||||
|
> {
|
||||||
|
private isoData = setIsoData(this.context);
|
||||||
|
private subscription: Subscription;
|
||||||
|
private emptyState: RegistrationApplicationsState = {
|
||||||
|
unreadOrAll: UnreadOrAll.Unread,
|
||||||
|
applications: [],
|
||||||
|
page: 1,
|
||||||
|
site_view: this.isoData.site_res.site_view,
|
||||||
|
loading: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = this.emptyState;
|
||||||
|
this.handlePageChange = this.handlePageChange.bind(this);
|
||||||
|
|
||||||
|
if (!UserService.Instance.myUserInfo && isBrowser()) {
|
||||||
|
toast(i18n.t("not_logged_in"), "danger");
|
||||||
|
this.context.router.history.push(`/login`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parseMessage = this.parseMessage.bind(this);
|
||||||
|
this.subscription = wsSubscribe(this.parseMessage);
|
||||||
|
|
||||||
|
// Only fetch the data if coming from another route
|
||||||
|
if (this.isoData.path == this.context.router.route.match.url) {
|
||||||
|
this.state.applications =
|
||||||
|
this.isoData.routeData[0].registration_applications || []; // TODO test
|
||||||
|
this.state.loading = false;
|
||||||
|
} else {
|
||||||
|
this.refetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
setupTippy();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (isBrowser()) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get documentTitle(): string {
|
||||||
|
return `@${
|
||||||
|
UserService.Instance.myUserInfo.local_user_view.person.name
|
||||||
|
} ${i18n.t("registration_applications")} - ${
|
||||||
|
this.state.site_view.site.name
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div class="container">
|
||||||
|
{this.state.loading ? (
|
||||||
|
<h5>
|
||||||
|
<Spinner large />
|
||||||
|
</h5>
|
||||||
|
) : (
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<HtmlTags
|
||||||
|
title={this.documentTitle}
|
||||||
|
path={this.context.router.route.match.url}
|
||||||
|
/>
|
||||||
|
<h5 class="mb-2">{i18n.t("registration_applications")}</h5>
|
||||||
|
{this.selects()}
|
||||||
|
{this.applicationList()}
|
||||||
|
<Paginator
|
||||||
|
page={this.state.page}
|
||||||
|
onChange={this.handlePageChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unreadOrAllRadios() {
|
||||||
|
return (
|
||||||
|
<div class="btn-group btn-group-toggle flex-wrap mb-2">
|
||||||
|
<label
|
||||||
|
className={`btn btn-outline-secondary pointer
|
||||||
|
${this.state.unreadOrAll == UnreadOrAll.Unread && "active"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={UnreadOrAll.Unread}
|
||||||
|
checked={this.state.unreadOrAll == UnreadOrAll.Unread}
|
||||||
|
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t("unread")}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
className={`btn btn-outline-secondary pointer
|
||||||
|
${this.state.unreadOrAll == UnreadOrAll.All && "active"}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={UnreadOrAll.All}
|
||||||
|
checked={this.state.unreadOrAll == UnreadOrAll.All}
|
||||||
|
onChange={linkEvent(this, this.handleUnreadOrAllChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t("all")}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
selects() {
|
||||||
|
return (
|
||||||
|
<div className="mb-2">
|
||||||
|
<span class="mr-3">{this.unreadOrAllRadios()}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationList() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{this.state.applications.map(ra => (
|
||||||
|
<>
|
||||||
|
<hr />
|
||||||
|
<RegistrationApplication
|
||||||
|
key={ra.registration_application.id}
|
||||||
|
application={ra}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
|
||||||
|
i.state.unreadOrAll = Number(event.target.value);
|
||||||
|
i.state.page = 1;
|
||||||
|
i.setState(i.state);
|
||||||
|
i.refetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePageChange(page: number) {
|
||||||
|
this.setState({ page });
|
||||||
|
this.refetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
|
||||||
|
let promises: Promise<any>[] = [];
|
||||||
|
|
||||||
|
let form: ListRegistrationApplications = {
|
||||||
|
unread_only: true,
|
||||||
|
page: 1,
|
||||||
|
limit: fetchLimit,
|
||||||
|
auth: req.auth,
|
||||||
|
};
|
||||||
|
promises.push(req.client.listRegistrationApplications(form));
|
||||||
|
|
||||||
|
return promises;
|
||||||
|
}
|
||||||
|
|
||||||
|
refetch() {
|
||||||
|
let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread;
|
||||||
|
let form: ListRegistrationApplications = {
|
||||||
|
unread_only: unread_only,
|
||||||
|
page: this.state.page,
|
||||||
|
limit: fetchLimit,
|
||||||
|
auth: authField(),
|
||||||
|
};
|
||||||
|
WebSocketService.Instance.send(wsClient.listRegistrationApplications(form));
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMessage(msg: any) {
|
||||||
|
let op = wsUserOp(msg);
|
||||||
|
console.log(msg);
|
||||||
|
if (msg.error) {
|
||||||
|
toast(i18n.t(msg.error), "danger");
|
||||||
|
return;
|
||||||
|
} else if (msg.reconnect) {
|
||||||
|
this.refetch();
|
||||||
|
} else if (op == UserOperation.ListRegistrationApplications) {
|
||||||
|
let data = wsJsonToRes<ListRegistrationApplicationsResponse>(msg).data;
|
||||||
|
this.state.applications = data.registration_applications;
|
||||||
|
this.state.loading = false;
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.ApproveRegistrationApplication) {
|
||||||
|
let data = wsJsonToRes<RegistrationApplicationResponse>(msg).data;
|
||||||
|
updateRegistrationApplicationRes(
|
||||||
|
data.registration_application,
|
||||||
|
this.state.applications
|
||||||
|
);
|
||||||
|
let uacs = UserService.Instance.unreadApplicationCountSub;
|
||||||
|
// Minor bug, where if the application switches from deny to approve, the count will still go down
|
||||||
|
uacs.next(uacs.getValue() - 1);
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,11 +29,11 @@ import {
|
||||||
wsSubscribe,
|
wsSubscribe,
|
||||||
wsUserOp,
|
wsUserOp,
|
||||||
} from "../../utils";
|
} from "../../utils";
|
||||||
import { CommentReport } from "../comment/comment_report";
|
import { CommentReport } from "../comment/comment-report";
|
||||||
import { HtmlTags } from "../common/html-tags";
|
import { HtmlTags } from "../common/html-tags";
|
||||||
import { Spinner } from "../common/icon";
|
import { Spinner } from "../common/icon";
|
||||||
import { Paginator } from "../common/paginator";
|
import { Paginator } from "../common/paginator";
|
||||||
import { PostReport } from "../post/post_report";
|
import { PostReport } from "../post/post-report";
|
||||||
|
|
||||||
enum UnreadOrAll {
|
enum UnreadOrAll {
|
||||||
Unread,
|
Unread,
|
||||||
|
|
|
@ -1108,6 +1108,11 @@ export class Settings extends Component<any, SettingsState> {
|
||||||
let op = wsUserOp(msg);
|
let op = wsUserOp(msg);
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
if (msg.error) {
|
if (msg.error) {
|
||||||
|
this.setState({
|
||||||
|
saveUserSettingsLoading: false,
|
||||||
|
changePasswordLoading: false,
|
||||||
|
deleteAccountLoading: false,
|
||||||
|
});
|
||||||
toast(i18n.t(msg.error), "danger");
|
toast(i18n.t(msg.error), "danger");
|
||||||
return;
|
return;
|
||||||
} else if (op == UserOperation.SaveUserSettings) {
|
} else if (op == UserOperation.SaveUserSettings) {
|
||||||
|
|
97
src/shared/components/person/verify-email.tsx
Normal file
97
src/shared/components/person/verify-email.tsx
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
import { Component } from "inferno";
|
||||||
|
import {
|
||||||
|
SiteView,
|
||||||
|
UserOperation,
|
||||||
|
VerifyEmail as VerifyEmailForm,
|
||||||
|
VerifyEmailResponse,
|
||||||
|
} from "lemmy-js-client";
|
||||||
|
import { Subscription } from "rxjs";
|
||||||
|
import { i18n } from "../../i18next";
|
||||||
|
import { WebSocketService } from "../../services";
|
||||||
|
import {
|
||||||
|
isBrowser,
|
||||||
|
setIsoData,
|
||||||
|
toast,
|
||||||
|
wsClient,
|
||||||
|
wsJsonToRes,
|
||||||
|
wsSubscribe,
|
||||||
|
wsUserOp,
|
||||||
|
} from "../../utils";
|
||||||
|
import { HtmlTags } from "../common/html-tags";
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
verifyEmailForm: VerifyEmailForm;
|
||||||
|
site_view: SiteView;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VerifyEmail extends Component<any, State> {
|
||||||
|
private isoData = setIsoData(this.context);
|
||||||
|
private subscription: Subscription;
|
||||||
|
|
||||||
|
emptyState: State = {
|
||||||
|
verifyEmailForm: {
|
||||||
|
token: this.props.match.params.token,
|
||||||
|
},
|
||||||
|
site_view: this.isoData.site_res.site_view,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = this.emptyState;
|
||||||
|
|
||||||
|
this.parseMessage = this.parseMessage.bind(this);
|
||||||
|
this.subscription = wsSubscribe(this.parseMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
WebSocketService.Instance.send(
|
||||||
|
wsClient.verifyEmail(this.state.verifyEmailForm)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (isBrowser()) {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get documentTitle(): string {
|
||||||
|
return `${i18n.t("verify_email")} - ${this.state.site_view.site.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div class="container">
|
||||||
|
<HtmlTags
|
||||||
|
title={this.documentTitle}
|
||||||
|
path={this.context.router.route.match.url}
|
||||||
|
/>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-lg-6 offset-lg-3 mb-4">
|
||||||
|
<h5>{i18n.t("verify_email")}</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
parseMessage(msg: any) {
|
||||||
|
let op = wsUserOp(msg);
|
||||||
|
console.log(msg);
|
||||||
|
if (msg.error) {
|
||||||
|
toast(i18n.t(msg.error), "danger");
|
||||||
|
this.setState(this.state);
|
||||||
|
this.props.history.push("/");
|
||||||
|
return;
|
||||||
|
} else if (op == UserOperation.VerifyEmail) {
|
||||||
|
let data = wsJsonToRes<VerifyEmailResponse>(msg).data;
|
||||||
|
if (data) {
|
||||||
|
toast(i18n.t("email_verified"));
|
||||||
|
this.state = this.emptyState;
|
||||||
|
this.setState(this.state);
|
||||||
|
this.props.history.push("/login");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,9 @@ export class PostReport extends Component<PostReportProps, any> {
|
||||||
render() {
|
render() {
|
||||||
let r = this.props.report;
|
let r = this.props.report;
|
||||||
let post = r.post;
|
let post = r.post;
|
||||||
|
let tippyContent = i18n.t(
|
||||||
|
r.post_report.resolved ? "unresolve_report" : "resolve_report"
|
||||||
|
);
|
||||||
|
|
||||||
// Set the original post data ( a troll could change it )
|
// Set the original post data ( a troll could change it )
|
||||||
post.name = r.post_report.original_post_name;
|
post.name = r.post_report.original_post_name;
|
||||||
|
@ -70,12 +73,8 @@ export class PostReport extends Component<PostReportProps, any> {
|
||||||
<button
|
<button
|
||||||
className="btn btn-link btn-animate text-muted py-0"
|
className="btn btn-link btn-animate text-muted py-0"
|
||||||
onClick={linkEvent(this, this.handleResolveReport)}
|
onClick={linkEvent(this, this.handleResolveReport)}
|
||||||
data-tippy-content={
|
data-tippy-content={tippyContent}
|
||||||
r.post_report.resolved ? "unresolve_report" : "resolve_report"
|
aria-label={tippyContent}
|
||||||
}
|
|
||||||
aria-label={
|
|
||||||
r.post_report.resolved ? "unresolve_report" : "resolve_report"
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
icon="check"
|
icon="check"
|
|
@ -6,14 +6,16 @@ import { AdminSettings } from "./components/home/admin-settings";
|
||||||
import { Home } from "./components/home/home";
|
import { Home } from "./components/home/home";
|
||||||
import { Instances } from "./components/home/instances";
|
import { Instances } from "./components/home/instances";
|
||||||
import { Login } from "./components/home/login";
|
import { Login } from "./components/home/login";
|
||||||
import { PasswordChange } from "./components/home/password_change";
|
|
||||||
import { Setup } from "./components/home/setup";
|
import { Setup } from "./components/home/setup";
|
||||||
import { Signup } from "./components/home/signup";
|
import { Signup } from "./components/home/signup";
|
||||||
import { Modlog } from "./components/modlog";
|
import { Modlog } from "./components/modlog";
|
||||||
import { Inbox } from "./components/person/inbox";
|
import { Inbox } from "./components/person/inbox";
|
||||||
|
import { PasswordChange } from "./components/person/password-change";
|
||||||
import { Profile } from "./components/person/profile";
|
import { Profile } from "./components/person/profile";
|
||||||
|
import { RegistrationApplications } from "./components/person/registration-applications";
|
||||||
import { Reports } from "./components/person/reports";
|
import { Reports } from "./components/person/reports";
|
||||||
import { Settings } from "./components/person/settings";
|
import { Settings } from "./components/person/settings";
|
||||||
|
import { VerifyEmail } from "./components/person/verify-email";
|
||||||
import { CreatePost } from "./components/post/create-post";
|
import { CreatePost } from "./components/post/create-post";
|
||||||
import { Post } from "./components/post/post";
|
import { Post } from "./components/post/post";
|
||||||
import { CreatePrivateMessage } from "./components/private_message/create-private-message";
|
import { CreatePrivateMessage } from "./components/private_message/create-private-message";
|
||||||
|
@ -128,6 +130,11 @@ export const routes: IRoutePropsWithFetch[] = [
|
||||||
component: Reports,
|
component: Reports,
|
||||||
fetchInitialData: req => Reports.fetchInitialData(req),
|
fetchInitialData: req => Reports.fetchInitialData(req),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `/registration_applications`,
|
||||||
|
component: RegistrationApplications,
|
||||||
|
fetchInitialData: req => RegistrationApplications.fetchInitialData(req),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: `/search/q/:q/type/:type/sort/:sort/listing_type/:listing_type/community_id/:community_id/creator_id/:creator_id/page/:page`,
|
path: `/search/q/:q/type/:type/sort/:sort/listing_type/:listing_type/community_id/:community_id/creator_id/:creator_id/page/:page`,
|
||||||
component: Search,
|
component: Search,
|
||||||
|
@ -142,5 +149,9 @@ export const routes: IRoutePropsWithFetch[] = [
|
||||||
path: `/password_change/:token`,
|
path: `/password_change/:token`,
|
||||||
component: PasswordChange,
|
component: PasswordChange,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `/verify_email/:token`,
|
||||||
|
component: VerifyEmail,
|
||||||
|
},
|
||||||
{ path: `/instances`, component: Instances },
|
{ path: `/instances`, component: Instances },
|
||||||
];
|
];
|
||||||
|
|
|
@ -20,6 +20,8 @@ export class UserService {
|
||||||
new BehaviorSubject<number>(0);
|
new BehaviorSubject<number>(0);
|
||||||
public unreadReportCountSub: BehaviorSubject<number> =
|
public unreadReportCountSub: BehaviorSubject<number> =
|
||||||
new BehaviorSubject<number>(0);
|
new BehaviorSubject<number>(0);
|
||||||
|
public unreadApplicationCountSub: BehaviorSubject<number> =
|
||||||
|
new BehaviorSubject<number>(0);
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
if (this.auth) {
|
if (this.auth) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
PostReportView,
|
PostReportView,
|
||||||
PostView,
|
PostView,
|
||||||
PrivateMessageView,
|
PrivateMessageView,
|
||||||
|
RegistrationApplicationView,
|
||||||
Search,
|
Search,
|
||||||
SearchResponse,
|
SearchResponse,
|
||||||
SearchType,
|
SearchType,
|
||||||
|
@ -1105,6 +1106,20 @@ export function updateCommentReportRes(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function updateRegistrationApplicationRes(
|
||||||
|
data: RegistrationApplicationView,
|
||||||
|
applications: RegistrationApplicationView[]
|
||||||
|
) {
|
||||||
|
let found = applications.find(
|
||||||
|
ra => ra.registration_application.id == data.registration_application.id
|
||||||
|
);
|
||||||
|
if (found) {
|
||||||
|
found.registration_application = data.registration_application;
|
||||||
|
found.admin = data.admin;
|
||||||
|
found.creator_local_user = data.creator_local_user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
|
export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
|
||||||
let nodes: CommentNodeI[] = [];
|
let nodes: CommentNodeI[] = [];
|
||||||
for (let comment of comments) {
|
for (let comment of comments) {
|
||||||
|
|
|
@ -4997,10 +4997,10 @@ lcid@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
invert-kv "^1.0.0"
|
invert-kv "^1.0.0"
|
||||||
|
|
||||||
lemmy-js-client@0.14.0-rc.1:
|
lemmy-js-client@0.15.0-rc.6:
|
||||||
version "0.14.0-rc.1"
|
version "0.15.0-rc.6"
|
||||||
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.14.0-rc.1.tgz#c714d5f308fa20d5244db3844630f7b197eafa1c"
|
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.15.0-rc.6.tgz#5f8552488ed82b8c0962c158edccb8ce1d56389e"
|
||||||
integrity sha512-UF3I+80WTYWwQg2+96HTl0O2Yv0wy6rYFjlLNyzfqMXUZBnsr1O/SdJD1/9yAFPFbGkKgWusdncLoGgzFyn8eg==
|
integrity sha512-eSEZ5+F2ScKVtx+wwjdReHirJBNLQL2YdTV4aMCBWaSsxfsXUcz18/urbNxo+fNMc7Q4u0aRd3737yKBeMP9Kw==
|
||||||
|
|
||||||
levn@^0.4.1:
|
levn@^0.4.1:
|
||||||
version "0.4.1"
|
version "0.4.1"
|
||||||
|
|
Loading…
Reference in a new issue