mirror of https://github.com/vector-im/riot-web
WIP
parent
d6af5b3bbd
commit
e80dba9414
|
@ -15,16 +15,88 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
.mx_HostSignupDialog {
|
||||
min-height: 531px;
|
||||
max-height: 600px;
|
||||
width: 580px;
|
||||
|
||||
.mx_HostSignupDialog_info {
|
||||
text-align: center;
|
||||
|
||||
.mx_HostSignupDialog_content {
|
||||
margin-top: 64px;
|
||||
margin-bottom: 45px;
|
||||
.mx_HostSignupDialog_content_top {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.mx_HostSignupDialog_paragraphs {
|
||||
text-align: left;
|
||||
padding-left: 25%;
|
||||
padding-right: 25%;
|
||||
}
|
||||
|
||||
.mx_HostSignupDialog_buttons {
|
||||
margin-bottom: 24px;
|
||||
|
||||
button {
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
min-height: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_HostSignupDialog_text_dark {
|
||||
color: $primary-fg-color;
|
||||
}
|
||||
|
||||
.mx_HostSignupDialog_text_light {
|
||||
color: $secondary-fg-color;
|
||||
}
|
||||
|
||||
.mx_HostSignup_maximize_button {
|
||||
mask: url('$(res)/img/feather-customised/widget/maximise.svg');
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center;
|
||||
mask-size: cover;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background-color: $dialog-close-fg-color;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.mx_HostSignup_persisted {
|
||||
width: 580px;
|
||||
height: 600px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mx_HostSignupDialog_minimized {
|
||||
position: fixed;
|
||||
bottom: 80px;
|
||||
right: 26px;
|
||||
width: 314px;
|
||||
height: 217px;
|
||||
overflow: hidden;
|
||||
|
||||
&.mx_Dialog {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.mx_Dialog_title {
|
||||
text-align: left !important;
|
||||
padding-left: 20px;
|
||||
font-size: $font-15px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
|
@ -34,21 +106,3 @@ limitations under the License.
|
|||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.mx_HostSignup_persisted {
|
||||
width: 580px;
|
||||
height: 600px;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.mx_HostSignupDialog_minimized {
|
||||
position: fixed;
|
||||
bottom: 100px;
|
||||
right: 100px;
|
||||
width: 200px;
|
||||
height: 120px;
|
||||
overflow: hidden;
|
||||
z-index: 6000;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ 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;
|
||||
|
@ -274,7 +275,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
|
||||
let topSection;
|
||||
const signupLink = getHostingLink("user-context-menu");
|
||||
const hostSignupConfig = SdkConfig.get().host_signup;
|
||||
const hostSignupConfig: IHostSignupConfig = SdkConfig.get().hostSignup;
|
||||
if (MatrixClientPeg.get().isGuest()) {
|
||||
topSection = (
|
||||
<div className="mx_UserMenu_contextMenu_header mx_UserMenu_contextMenu_guestPrompts">
|
||||
|
@ -297,7 +298,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
|||
} else if (signupLink || hostSignupConfig) {
|
||||
let hostSignupAction;
|
||||
if (hostSignupConfig && hostSignupConfig.url) {
|
||||
// If host_signup.domains is set to a non-empty array, only show
|
||||
// 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();
|
||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import Modal from "../../../Modal";
|
||||
import PersistedElement from "../elements/PersistedElement";
|
||||
import QuestionDialog from './QuestionDialog';
|
||||
|
@ -23,7 +24,12 @@ import {_t} from "../../../languageHandler";
|
|||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||
import {HostSignupStore} from "../../../stores/HostSignupStore";
|
||||
import {OwnProfileStore} from "../../../stores/OwnProfileStore";
|
||||
import {IPostmessage, IPostmessageResponseData, PostmessageAction} from "./HostSignupDialogTypes";
|
||||
import {
|
||||
IHostSignupConfig,
|
||||
IPostmessage,
|
||||
IPostmessageResponseData,
|
||||
PostmessageAction,
|
||||
} from "./HostSignupDialogTypes";
|
||||
|
||||
interface IProps {}
|
||||
|
||||
|
@ -32,11 +38,12 @@ interface IState {
|
|||
error: string;
|
||||
loadIframe: boolean;
|
||||
minimized: boolean;
|
||||
termsAccepted: boolean;
|
||||
}
|
||||
|
||||
export default class HostSignupDialog extends React.PureComponent<IProps, IState> {
|
||||
private iframeRef: React.RefObject<HTMLIFrameElement> = React.createRef();
|
||||
private readonly hostSignupSetupUrl: string;
|
||||
private readonly config: IHostSignupConfig;
|
||||
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
@ -46,13 +53,14 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
error: null,
|
||||
loadIframe: false,
|
||||
minimized: false,
|
||||
termsAccepted: false,
|
||||
};
|
||||
|
||||
this.hostSignupSetupUrl = SdkConfig.get().host_signup.url;
|
||||
this.config = SdkConfig.get().hostSignup;
|
||||
}
|
||||
|
||||
private messageHandler = async (message: IPostmessage) => {
|
||||
if (!this.hostSignupSetupUrl.startsWith(message.origin)) {
|
||||
if (!this.config.url.startsWith(message.origin)) {
|
||||
return;
|
||||
}
|
||||
switch (message.data.action) {
|
||||
|
@ -73,14 +81,16 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
});
|
||||
break;
|
||||
case PostmessageAction.CloseDialog:
|
||||
return this.onFinished(true);
|
||||
return this.closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
private maximizeDialog = () => {
|
||||
this.setState({
|
||||
minimized: false,
|
||||
});
|
||||
if (this.state.minimized) {
|
||||
this.setState({
|
||||
minimized: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private minimizeDialog = () => {
|
||||
|
@ -97,8 +107,8 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
return HostSignupStore.instance.setHostSignupActive(false);
|
||||
}
|
||||
|
||||
private onFinished = async (result: boolean) => {
|
||||
if (result || this.state.completed) {
|
||||
private onCloseClick = async () => {
|
||||
if (this.state.completed) {
|
||||
// We're done, close
|
||||
return this.closeDialog();
|
||||
} else {
|
||||
|
@ -121,7 +131,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
}
|
||||
|
||||
private sendMessage = (message: IPostmessageResponseData) => {
|
||||
this.iframeRef.current.contentWindow.postMessage(message, this.hostSignupSetupUrl);
|
||||
this.iframeRef.current.contentWindow.postMessage(message, this.config.url);
|
||||
}
|
||||
|
||||
private async sendAccountDetails() {
|
||||
|
@ -141,6 +151,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
openIdToken: openIdToken.access_token,
|
||||
serverName: await MatrixClientPeg.get().getDomain(),
|
||||
userLocalpart: await MatrixClientPeg.get().getUserIdLocalpart(),
|
||||
termsAccepted: this.state.termsAccepted,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -152,6 +163,25 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
});
|
||||
}
|
||||
|
||||
private onStartClick = () => {
|
||||
Modal.createDialog(
|
||||
QuestionDialog,
|
||||
{
|
||||
title: this.config.termsDialog.title,
|
||||
description: this.config.termsDialog.text,
|
||||
button: this.config.termsDialog.acceptText,
|
||||
onFinished: result => {
|
||||
if (result) {
|
||||
this.setState({
|
||||
termsAccepted: true,
|
||||
});
|
||||
this.loadIframe();
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (HostSignupStore.instance.isHostSignupActive) {
|
||||
// Run the close dialog actions if we're still active, otherwise good to go
|
||||
|
@ -164,41 +194,92 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
<div className="mx_HostSignup_persisted">
|
||||
<PersistedElement key="host_signup" persistKey="host_signup">
|
||||
<div className={this.state.minimized ? "" : "mx_Dialog_wrapper"}>
|
||||
<div className={
|
||||
this.state.minimized ? "mx_HostSignupDialog_minimized" : "mx_HostSignupDialog mx_Dialog"
|
||||
<div className={["mx_Dialog",
|
||||
this.state.minimized ? "mx_HostSignupDialog_minimized" : "mx_HostSignupDialog"].join(" ")
|
||||
}>
|
||||
{this.state.loadIframe &&
|
||||
<iframe
|
||||
src={this.hostSignupSetupUrl}
|
||||
ref={this.iframeRef}
|
||||
sandbox="allow-forms allow-scripts allow-same-origin"
|
||||
/>
|
||||
<>
|
||||
{this.state.minimized &&
|
||||
<div className="mx_Dialog_header mx_Dialog_headerWithButton">
|
||||
<div className="mx_Dialog_title">
|
||||
{this.config.minimizedDialogTitle}
|
||||
</div>
|
||||
<AccessibleButton
|
||||
className="mx_HostSignup_maximize_button"
|
||||
onClick={this.maximizeDialog}
|
||||
aria-label={_t("Maximize dialog")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{!this.state.minimized &&
|
||||
<div className="mx_Dialog_header mx_Dialog_headerWithCancel">
|
||||
<AccessibleButton
|
||||
onClick={this.onCloseClick} className="mx_Dialog_cancelButton"
|
||||
aria-label={_t("Close dialog")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<iframe
|
||||
src={this.config.url}
|
||||
ref={this.iframeRef}
|
||||
sandbox="allow-forms allow-scripts allow-same-origin"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
{!this.state.loadIframe &&
|
||||
<div className="mx_HostSignupDialog_info">
|
||||
{this.state.minimized &&
|
||||
<button onClick={this.maximizeDialog}>Maximize</button>
|
||||
{this.config.info.image &&
|
||||
<img
|
||||
alt={this.config.info.image.alt}
|
||||
src={this.config.info.image.src}
|
||||
/>
|
||||
}
|
||||
<img
|
||||
alt="image of planet"
|
||||
src={require("../../../../res/img/host_signup.png")}
|
||||
/>
|
||||
<div className="mx_HostSignupDialog_content">
|
||||
<h1>Unlock the power of Element</h1>
|
||||
<p>
|
||||
Congratulations! You taken your first steps into unlocking the full
|
||||
power of the Element app. In a few minutes, you'll be able to
|
||||
see how powerful our
|
||||
Matrix services are and take control of your conversation data.
|
||||
</p>
|
||||
<div className="mx_HostSignupDialog_content_top">
|
||||
<h1 className="mx_HostSignupDialog_text_dark">
|
||||
{this.config.info.title}
|
||||
</h1>
|
||||
{this.config.info.additionalParagraphs &&
|
||||
<div className="mx_HostSignupDialog_paragraphs">
|
||||
{this.config.info.additionalParagraphs.map((para, index) => {
|
||||
return <p className="mx_HostSignupDialog_text_light" key={index}>
|
||||
{para}
|
||||
</p>;
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
{this.config.info.additionalInfoLink &&
|
||||
<p><small>
|
||||
<a href={this.config.info.additionalInfoLink.href} target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
title={this.config.info.additionalInfoLink.text}
|
||||
>
|
||||
{this.config.info.additionalInfoLink.text}
|
||||
</a>
|
||||
</small></p>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={this.closeDialog}>Maybe later</button>
|
||||
<button onClick={this.loadIframe} className="mx_Dialog_primary">
|
||||
Lets get started
|
||||
<div className="mx_HostSignupDialog_buttons">
|
||||
{/*TODO: what about accessibility? the signup flow is possibly not reader optimized*/}
|
||||
<button onClick={this.closeDialog}>{this.config.info.cancelText}</button>
|
||||
<button onClick={this.onStartClick} className="mx_Dialog_primary">
|
||||
{this.config.info.continueText}
|
||||
</button>
|
||||
<button onClick={this.minimizeDialog}>Minimize</button>
|
||||
</div>
|
||||
{this.config.info.footer &&
|
||||
<div className="mx_HostSignupDialog_text_light">
|
||||
<small>
|
||||
<p>
|
||||
{this.config.info.footer.image &&
|
||||
<img
|
||||
alt={this.config.info.footer.image.alt}
|
||||
src={this.config.info.footer.image.src}
|
||||
/>
|
||||
}
|
||||
{this.config.info.footer.text}
|
||||
</p>
|
||||
</small>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{this.state.error &&
|
||||
|
@ -208,7 +289,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
|||
}
|
||||
</div>
|
||||
{!this.state.minimized &&
|
||||
<div className="mx_Dialog_background" />
|
||||
<div className="mx_Dialog_background mx_HostSignupDialog_background" />
|
||||
}
|
||||
</div>
|
||||
</PersistedElement>
|
||||
|
|
|
@ -29,6 +29,7 @@ interface IAccountData {
|
|||
openIdToken: string;
|
||||
serverName: string;
|
||||
userLocalpart: string;
|
||||
termsAccepted: boolean;
|
||||
}
|
||||
|
||||
export interface IPostmessageRequestData {
|
||||
|
@ -44,3 +45,43 @@ export interface IPostmessage {
|
|||
data: IPostmessageRequestData;
|
||||
origin: string;
|
||||
}
|
||||
|
||||
interface IImage {
|
||||
alt: string;
|
||||
src: string;
|
||||
}
|
||||
|
||||
interface ILink {
|
||||
href: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface IInfoFooter {
|
||||
image: IImage;
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface IHostSignupInfoConfig {
|
||||
additionalInfoLink?: ILink;
|
||||
additionalParagraphs?: Array<string>;
|
||||
cancelText: string;
|
||||
continueText: string;
|
||||
footer?: IInfoFooter;
|
||||
image?: IImage;
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface IHostSignupTermsDialogConfig {
|
||||
acceptText: string;
|
||||
termsDocuments: Array<ILink>;
|
||||
text: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface IHostSignupConfig {
|
||||
domains: Array<string>;
|
||||
info: IHostSignupInfoConfig;
|
||||
minimizedDialogTitle: string;
|
||||
termsDialog: IHostSignupTermsDialogConfig;
|
||||
url: string;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue