Merge pull request #5450 from matrix-org/jaywink/hosting-provider-iframe
Add host signup modal with iframe
This commit is contained in:
commit
fa5df314a1
12 changed files with 658 additions and 22 deletions
45
src/components/structures/HostSignupAction.tsx
Normal file
45
src/components/structures/HostSignupAction.tsx
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
IconizedContextMenuOption,
|
||||
IconizedContextMenuOptionList,
|
||||
} from "../views/context_menus/IconizedContextMenu";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { HostSignupStore } from "../../stores/HostSignupStore";
|
||||
|
||||
interface IProps {}
|
||||
|
||||
interface IState {}
|
||||
|
||||
export default class HostSignupAction extends React.PureComponent<IProps, IState> {
|
||||
private openDialog = async () => {
|
||||
await HostSignupStore.instance.setHostSignupActive(true);
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<IconizedContextMenuOptionList>
|
||||
<IconizedContextMenuOption
|
||||
iconClassName="mx_UserMenu_iconHosting"
|
||||
label={_t("Upgrade to pro")}
|
||||
onClick={this.openDialog}
|
||||
/>
|
||||
</IconizedContextMenuOptionList>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@ import { ToggleRightPanelPayload } from "../../dispatcher/payloads/ToggleRightPa
|
|||
import { IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
||||
import Modal from "../../Modal";
|
||||
import { ICollapseConfig } from "../../resizer/distributors/collapse";
|
||||
import HostSignupContainer from '../views/host_signup/HostSignupContainer';
|
||||
|
||||
// We need to fetch each pinned message individually (if we don't already have it)
|
||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||
|
@ -648,6 +649,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
|||
</div>
|
||||
<CallContainer />
|
||||
<NonUrgentToastContainer />
|
||||
<HostSignupContainer />
|
||||
</MatrixClientContext.Provider>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -28,7 +28,6 @@ import Modal from "../../Modal";
|
|||
import LogoutDialog from "../views/dialogs/LogoutDialog";
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import {getCustomTheme} from "../../theme";
|
||||
import {getHostingLink} from "../../utils/HostingLink";
|
||||
import AccessibleButton, {ButtonEvent} from "../views/elements/AccessibleButton";
|
||||
import SdkConfig from "../../SdkConfig";
|
||||
import {getHomePageUrl} from "../../utils/pages";
|
||||
|
@ -51,6 +50,8 @@ import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
|||
import ErrorDialog from "../views/dialogs/ErrorDialog";
|
||||
import EditCommunityPrototypeDialog from "../views/dialogs/EditCommunityPrototypeDialog";
|
||||
import {UIFeature} from "../../settings/UIFeature";
|
||||
import HostSignupAction from "./HostSignupAction";
|
||||
import {IHostSignupConfig} from "../views/dialogs/HostSignupDialogTypes";
|
||||
|
||||
interface IProps {
|
||||
isMinimized: boolean;
|
||||
|
@ -272,7 +273,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
const prototypeCommunityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
|
||||
|
||||
let topSection;
|
||||
const signupLink = getHostingLink("user-context-menu");
|
||||
const hostSignupConfig: IHostSignupConfig = SdkConfig.get().hostSignup;
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
topSection = (
|
||||
<div className="mx_UserMenu_contextMenu_header mx_UserMenu_contextMenu_guestPrompts">
|
||||
|
@ -292,24 +293,19 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
})}
|
||||
</div>
|
||||
)
|
||||
} else if (signupLink) {
|
||||
topSection = (
|
||||
<div className="mx_UserMenu_contextMenu_header mx_UserMenu_contextMenu_hostingLink">
|
||||
{_t(
|
||||
"<a>Upgrade</a> to your own domain", {},
|
||||
{
|
||||
a: sub => (
|
||||
<a
|
||||
href={signupLink}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
tabIndex={-1}
|
||||
>{sub}</a>
|
||||
),
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
} else if (hostSignupConfig) {
|
||||
if (hostSignupConfig && hostSignupConfig.url) {
|
||||
// If hostSignup.domains is set to a non-empty array, only show
|
||||
// dialog if the user is on the domain or a subdomain.
|
||||
const hostSignupDomains = hostSignupConfig.domains || [];
|
||||
const mxDomain = MatrixClientPeg.get().getDomain();
|
||||
const validDomains = hostSignupDomains.filter(d => (d === mxDomain || mxDomain.endsWith(`.${d}`)));
|
||||
if (!hostSignupDomains || validDomains.length > 0) {
|
||||
topSection = <div onClick={this.onCloseMenu}>
|
||||
<HostSignupAction />
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let homeButton = null;
|
||||
|
|
291
src/components/views/dialogs/HostSignupDialog.tsx
Normal file
291
src/components/views/dialogs/HostSignupDialog.tsx
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import Modal from "../../../Modal";
|
||||
import PersistedElement from "../elements/PersistedElement";
|
||||
import QuestionDialog from './QuestionDialog';
|
||||
import SdkConfig from "../../../SdkConfig";
|
||||
import classNames from "classnames";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||
import { HostSignupStore } from "../../../stores/HostSignupStore";
|
||||
import { OwnProfileStore } from "../../../stores/OwnProfileStore";
|
||||
import {
|
||||
IHostSignupConfig,
|
||||
IPostmessage,
|
||||
IPostmessageResponseData,
|
||||
PostmessageAction,
|
||||
} from "./HostSignupDialogTypes";
|
||||
|
||||
const HOST_SIGNUP_KEY = "host_signup";
|
||||
|
||||
interface IProps {}
|
||||
|
||||
interface IState {
|
||||
completed: boolean;
|
||||
error: string;
|
||||
minimized: boolean;
|
||||
}
|
||||
|
||||
export default class HostSignupDialog extends React.PureComponent<IProps, IState> {
|
||||
private iframeRef: React.RefObject<HTMLIFrameElement> = React.createRef();
|
||||
private readonly config: IHostSignupConfig;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
completed: false,
|
||||
error: null,
|
||||
minimized: false,
|
||||
};
|
||||
|
||||
this.config = SdkConfig.get().hostSignup;
|
||||
}
|
||||
|
||||
private messageHandler = async (message: IPostmessage) => {
|
||||
if (!this.config.url.startsWith(message.origin)) {
|
||||
return;
|
||||
}
|
||||
switch (message.data.action) {
|
||||
case PostmessageAction.HostSignupAccountDetailsRequest:
|
||||
this.onAccountDetailsRequest();
|
||||
break;
|
||||
case PostmessageAction.Maximize:
|
||||
this.setState({
|
||||
minimized: false,
|
||||
});
|
||||
break;
|
||||
case PostmessageAction.Minimize:
|
||||
this.setState({
|
||||
minimized: true,
|
||||
});
|
||||
break;
|
||||
case PostmessageAction.SetupComplete:
|
||||
this.setState({
|
||||
completed: true,
|
||||
});
|
||||
break;
|
||||
case PostmessageAction.CloseDialog:
|
||||
return this.closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private maximizeDialog = () => {
|
||||
this.setState({
|
||||
minimized: false,
|
||||
});
|
||||
// Send this action to the iframe so it can act accordingly
|
||||
this.sendMessage({
|
||||
action: PostmessageAction.Maximize,
|
||||
});
|
||||
}
|
||||
|
||||
private minimizeDialog = () => {
|
||||
this.setState({
|
||||
minimized: true,
|
||||
});
|
||||
// Send this action to the iframe so it can act accordingly
|
||||
this.sendMessage({
|
||||
action: PostmessageAction.Minimize,
|
||||
});
|
||||
}
|
||||
|
||||
private closeDialog = async () => {
|
||||
window.removeEventListener("message", this.messageHandler);
|
||||
// Ensure we destroy the host signup persisted element
|
||||
PersistedElement.destroyElement("host_signup");
|
||||
// Finally clear the flag in
|
||||
return HostSignupStore.instance.setHostSignupActive(false);
|
||||
}
|
||||
|
||||
private onCloseClick = async () => {
|
||||
if (this.state.completed) {
|
||||
// We're done, close
|
||||
return this.closeDialog();
|
||||
} else {
|
||||
Modal.createDialog(
|
||||
QuestionDialog,
|
||||
{
|
||||
title: _t("Confirm abort of host creation"),
|
||||
description: _t(
|
||||
"Are you sure you wish to abort creation of the host? The process cannot be continued.",
|
||||
),
|
||||
button: _t("Abort"),
|
||||
onFinished: result => {
|
||||
if (result) {
|
||||
return this.closeDialog();
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private sendMessage = (message: IPostmessageResponseData) => {
|
||||
this.iframeRef.current.contentWindow.postMessage(message, this.config.url);
|
||||
}
|
||||
|
||||
private async sendAccountDetails() {
|
||||
const openIdToken = await MatrixClientPeg.get().getOpenIdToken();
|
||||
if (!openIdToken || !openIdToken.access_token) {
|
||||
console.warn("Failed to connect to homeserver for OpenID token.")
|
||||
this.setState({
|
||||
completed: true,
|
||||
error: _t("Failed to connect to your homeserver. Please close this dialog and try again."),
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.sendMessage({
|
||||
action: PostmessageAction.HostSignupAccountDetails,
|
||||
account: {
|
||||
accessToken: await MatrixClientPeg.get().getAccessToken(),
|
||||
name: OwnProfileStore.instance.displayName,
|
||||
openIdToken: openIdToken.access_token,
|
||||
serverName: await MatrixClientPeg.get().getDomain(),
|
||||
userLocalpart: await MatrixClientPeg.get().getUserIdLocalpart(),
|
||||
termsAccepted: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private onAccountDetailsDialogFinished = async (result) => {
|
||||
if (result) {
|
||||
return this.sendAccountDetails();
|
||||
}
|
||||
return this.closeDialog();
|
||||
}
|
||||
|
||||
private onAccountDetailsRequest = () => {
|
||||
const textComponent = (
|
||||
<>
|
||||
<p>
|
||||
{_t("Continuing temporarily allows the %(hostSignupBrand)s setup process to access your " +
|
||||
"account to fetch verified email addresses. This data is not stored.", {
|
||||
hostSignupBrand: this.config.brand,
|
||||
})}
|
||||
</p>
|
||||
<p>
|
||||
{_t("Learn more in our <privacyPolicyLink />, <termsOfServiceLink /> and <cookiePolicyLink />.",
|
||||
{},
|
||||
{
|
||||
cookiePolicyLink: () => (
|
||||
<a href={this.config.cookiePolicyUrl} target="_blank" rel="noreferrer noopener">
|
||||
{_t("Cookie Policy")}
|
||||
</a>
|
||||
),
|
||||
privacyPolicyLink: () => (
|
||||
<a href={this.config.privacyPolicyUrl} target="_blank" rel="noreferrer noopener">
|
||||
{_t("Privacy Policy")}
|
||||
</a>
|
||||
),
|
||||
termsOfServiceLink: () => (
|
||||
<a href={this.config.termsOfServiceUrl} target="_blank" rel="noreferrer noopener">
|
||||
{_t("Terms of Service")}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
Modal.createDialog(
|
||||
QuestionDialog,
|
||||
{
|
||||
title: _t("You should know"),
|
||||
description: textComponent,
|
||||
button: _t("Continue"),
|
||||
onFinished: this.onAccountDetailsDialogFinished,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
window.addEventListener("message", this.messageHandler);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (HostSignupStore.instance.isHostSignupActive) {
|
||||
// Run the close dialog actions if we're still active, otherwise good to go
|
||||
return this.closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<div className="mx_HostSignup_persisted">
|
||||
<PersistedElement key={HOST_SIGNUP_KEY} persistKey={HOST_SIGNUP_KEY}>
|
||||
<div className={classNames({ "mx_Dialog_wrapper": !this.state.minimized })}>
|
||||
<div
|
||||
className={classNames("mx_Dialog",
|
||||
{
|
||||
"mx_HostSignupDialog_minimized": this.state.minimized,
|
||||
"mx_HostSignupDialog": !this.state.minimized,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{this.state.minimized &&
|
||||
<div className="mx_Dialog_header mx_Dialog_headerWithButton">
|
||||
<div className="mx_Dialog_title">
|
||||
{_t("%(hostSignupBrand)s Setup", {
|
||||
hostSignupBrand: this.config.brand,
|
||||
})}
|
||||
</div>
|
||||
<AccessibleButton
|
||||
className="mx_HostSignup_maximize_button"
|
||||
onClick={this.maximizeDialog}
|
||||
aria-label={_t("Maximize dialog")}
|
||||
title={_t("Maximize dialog")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{!this.state.minimized &&
|
||||
<div className="mx_Dialog_header mx_Dialog_headerWithCancel">
|
||||
<AccessibleButton
|
||||
onClick={this.minimizeDialog}
|
||||
className="mx_HostSignup_minimize_button"
|
||||
aria-label={_t("Minimize dialog")}
|
||||
title={_t("Minimize dialog")}
|
||||
/>
|
||||
<AccessibleButton
|
||||
onClick={this.onCloseClick}
|
||||
className="mx_Dialog_cancelButton"
|
||||
aria-label={_t("Close dialog")}
|
||||
title={_t("Close dialog")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{this.state.error &&
|
||||
<div>
|
||||
{this.state.error}
|
||||
</div>
|
||||
}
|
||||
{!this.state.error &&
|
||||
<iframe
|
||||
src={this.config.url}
|
||||
ref={this.iframeRef}
|
||||
sandbox="allow-forms allow-scripts allow-same-origin allow-popups"
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</PersistedElement>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
56
src/components/views/dialogs/HostSignupDialogTypes.ts
Normal file
56
src/components/views/dialogs/HostSignupDialogTypes.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export enum PostmessageAction {
|
||||
CloseDialog = "close_dialog",
|
||||
HostSignupAccountDetails = "host_signup_account_details",
|
||||
HostSignupAccountDetailsRequest = "host_signup_account_details_request",
|
||||
Minimize = "host_signup_minimize",
|
||||
Maximize = "host_signup_maximize",
|
||||
SetupComplete = "setup_complete",
|
||||
}
|
||||
|
||||
interface IAccountData {
|
||||
accessToken: string;
|
||||
name: string;
|
||||
openIdToken: string;
|
||||
serverName: string;
|
||||
userLocalpart: string;
|
||||
termsAccepted: boolean;
|
||||
}
|
||||
|
||||
export interface IPostmessageRequestData {
|
||||
action: PostmessageAction;
|
||||
}
|
||||
|
||||
export interface IPostmessageResponseData {
|
||||
action: PostmessageAction;
|
||||
account?: IAccountData;
|
||||
}
|
||||
|
||||
export interface IPostmessage {
|
||||
data: IPostmessageRequestData;
|
||||
origin: string;
|
||||
}
|
||||
|
||||
export interface IHostSignupConfig {
|
||||
brand: string;
|
||||
cookiePolicyUrl: string;
|
||||
domains: Array<string>;
|
||||
privacyPolicyUrl: string;
|
||||
termsOfServiceUrl: string;
|
||||
url: string;
|
||||
}
|
36
src/components/views/host_signup/HostSignupContainer.tsx
Normal file
36
src/components/views/host_signup/HostSignupContainer.tsx
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import HostSignupDialog from "../dialogs/HostSignupDialog";
|
||||
import { HostSignupStore } from "../../../stores/HostSignupStore";
|
||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
|
||||
|
||||
const HostSignupContainer = () => {
|
||||
const [isActive, setIsActive] = useState(HostSignupStore.instance.isHostSignupActive);
|
||||
useEventEmitter(HostSignupStore.instance, UPDATE_EVENT, () => {
|
||||
setIsActive(HostSignupStore.instance.isHostSignupActive);
|
||||
});
|
||||
|
||||
return <div className="mx_HostSignupContainer">
|
||||
{isActive &&
|
||||
<HostSignupDialog />
|
||||
}
|
||||
</div>;
|
||||
};
|
||||
|
||||
export default HostSignupContainer
|
|
@ -2088,6 +2088,19 @@
|
|||
"Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. No match? <newIssueLink>Start a new one</newIssueLink>.": "Please view <existingIssuesLink>existing bugs on Github</existingIssuesLink> first. No match? <newIssueLink>Start a new one</newIssueLink>.",
|
||||
"PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> to help us track down the problem.": "PRO TIP: If you start a bug, please submit <debugLogsLink>debug logs</debugLogsLink> to help us track down the problem.",
|
||||
"Send feedback": "Send feedback",
|
||||
"Confirm abort of host creation": "Confirm abort of host creation",
|
||||
"Are you sure you wish to abort creation of the host? The process cannot be continued.": "Are you sure you wish to abort creation of the host? The process cannot be continued.",
|
||||
"Abort": "Abort",
|
||||
"Failed to connect to your homeserver. Please close this dialog and try again.": "Failed to connect to your homeserver. Please close this dialog and try again.",
|
||||
"Continuing temporarily allows the %(hostSignupBrand)s setup process to access your account to fetch verified email addresses. This data is not stored.": "Continuing temporarily allows the %(hostSignupBrand)s setup process to access your account to fetch verified email addresses. This data is not stored.",
|
||||
"Learn more in our <privacyPolicyLink />, <termsOfServiceLink /> and <cookiePolicyLink />.": "Learn more in our <privacyPolicyLink />, <termsOfServiceLink /> and <cookiePolicyLink />.",
|
||||
"Cookie Policy": "Cookie Policy",
|
||||
"Privacy Policy": "Privacy Policy",
|
||||
"Terms of Service": "Terms of Service",
|
||||
"You should know": "You should know",
|
||||
"%(hostSignupBrand)s Setup": "%(hostSignupBrand)s Setup",
|
||||
"Maximize dialog": "Maximize dialog",
|
||||
"Minimize dialog": "Minimize dialog",
|
||||
"Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.": "Verify this user to mark them as trusted. Trusting users gives you extra peace of mind when using end-to-end encrypted messages.",
|
||||
"Verifying this user will mark their session as trusted, and also mark your session as trusted to them.": "Verifying this user will mark their session as trusted, and also mark your session as trusted to them.",
|
||||
"Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.": "Verify this device to mark it as trusted. Trusting this device gives you and other users extra peace of mind when using end-to-end encrypted messages.",
|
||||
|
@ -2238,7 +2251,6 @@
|
|||
"Find others by phone or email": "Find others by phone or email",
|
||||
"Be found by phone or email": "Be found by phone or email",
|
||||
"Use bots, bridges, widgets and sticker packs": "Use bots, bridges, widgets and sticker packs",
|
||||
"Terms of Service": "Terms of Service",
|
||||
"To continue you need to accept the terms of this service.": "To continue you need to accept the terms of this service.",
|
||||
"Service": "Service",
|
||||
"Summary": "Summary",
|
||||
|
@ -2438,6 +2450,7 @@
|
|||
"Send a Direct Message": "Send a Direct Message",
|
||||
"Explore Public Rooms": "Explore Public Rooms",
|
||||
"Create a Group Chat": "Create a Group Chat",
|
||||
"Upgrade to pro": "Upgrade to pro",
|
||||
"Explore rooms": "Explore rooms",
|
||||
"Failed to reject invitation": "Failed to reject invitation",
|
||||
"Cannot create rooms in this community": "Cannot create rooms in this community",
|
||||
|
|
49
src/stores/HostSignupStore.ts
Normal file
49
src/stores/HostSignupStore.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||
import {AsyncStore} from "./AsyncStore";
|
||||
import {ActionPayload} from "../dispatcher/payloads";
|
||||
|
||||
interface IState {
|
||||
hostSignupActive?: boolean;
|
||||
}
|
||||
|
||||
export class HostSignupStore extends AsyncStore<IState> {
|
||||
private static internalInstance = new HostSignupStore();
|
||||
|
||||
private constructor() {
|
||||
super(defaultDispatcher, {hostSignupActive: false});
|
||||
}
|
||||
|
||||
public static get instance(): HostSignupStore {
|
||||
return HostSignupStore.internalInstance;
|
||||
}
|
||||
|
||||
public get isHostSignupActive(): boolean {
|
||||
return this.state.hostSignupActive;
|
||||
}
|
||||
|
||||
public async setHostSignupActive(status: boolean) {
|
||||
return this.updateState({
|
||||
hostSignupActive: status,
|
||||
});
|
||||
}
|
||||
|
||||
protected onDispatch(payload: ActionPayload) {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue