WIP
parent
d6af5b3bbd
commit
e80dba9414
|
@ -15,16 +15,88 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_HostSignupDialog {
|
.mx_HostSignupDialog {
|
||||||
|
min-height: 531px;
|
||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
width: 580px;
|
width: 580px;
|
||||||
|
|
||||||
.mx_HostSignupDialog_info {
|
.mx_HostSignupDialog_info {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
.mx_HostSignupDialog_content {
|
.mx_HostSignupDialog_content_top {
|
||||||
margin-top: 64px;
|
margin-bottom: 24px;
|
||||||
margin-bottom: 45px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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 {
|
iframe {
|
||||||
|
@ -34,21 +106,3 @@ limitations under the License.
|
||||||
background-color: #fff;
|
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 EditCommunityPrototypeDialog from "../views/dialogs/EditCommunityPrototypeDialog";
|
||||||
import {UIFeature} from "../../settings/UIFeature";
|
import {UIFeature} from "../../settings/UIFeature";
|
||||||
import HostSignupAction from "./HostSignupAction";
|
import HostSignupAction from "./HostSignupAction";
|
||||||
|
import {IHostSignupConfig} from "../views/dialogs/HostSignupDialogTypes";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
|
@ -274,7 +275,7 @@ export default class UserMenu extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
let topSection;
|
let topSection;
|
||||||
const signupLink = getHostingLink("user-context-menu");
|
const signupLink = getHostingLink("user-context-menu");
|
||||||
const hostSignupConfig = SdkConfig.get().host_signup;
|
const hostSignupConfig: IHostSignupConfig = SdkConfig.get().hostSignup;
|
||||||
if (MatrixClientPeg.get().isGuest()) {
|
if (MatrixClientPeg.get().isGuest()) {
|
||||||
topSection = (
|
topSection = (
|
||||||
<div className="mx_UserMenu_contextMenu_header mx_UserMenu_contextMenu_guestPrompts">
|
<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) {
|
} else if (signupLink || hostSignupConfig) {
|
||||||
let hostSignupAction;
|
let hostSignupAction;
|
||||||
if (hostSignupConfig && hostSignupConfig.url) {
|
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.
|
// dialog if the user is on the domain or a subdomain.
|
||||||
const hostSignupDomains = hostSignupConfig.domains || [];
|
const hostSignupDomains = hostSignupConfig.domains || [];
|
||||||
const mxDomain = MatrixClientPeg.get().getDomain();
|
const mxDomain = MatrixClientPeg.get().getDomain();
|
||||||
|
|
|
@ -15,6 +15,7 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import PersistedElement from "../elements/PersistedElement";
|
import PersistedElement from "../elements/PersistedElement";
|
||||||
import QuestionDialog from './QuestionDialog';
|
import QuestionDialog from './QuestionDialog';
|
||||||
|
@ -23,7 +24,12 @@ import {_t} from "../../../languageHandler";
|
||||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||||
import {HostSignupStore} from "../../../stores/HostSignupStore";
|
import {HostSignupStore} from "../../../stores/HostSignupStore";
|
||||||
import {OwnProfileStore} from "../../../stores/OwnProfileStore";
|
import {OwnProfileStore} from "../../../stores/OwnProfileStore";
|
||||||
import {IPostmessage, IPostmessageResponseData, PostmessageAction} from "./HostSignupDialogTypes";
|
import {
|
||||||
|
IHostSignupConfig,
|
||||||
|
IPostmessage,
|
||||||
|
IPostmessageResponseData,
|
||||||
|
PostmessageAction,
|
||||||
|
} from "./HostSignupDialogTypes";
|
||||||
|
|
||||||
interface IProps {}
|
interface IProps {}
|
||||||
|
|
||||||
|
@ -32,11 +38,12 @@ interface IState {
|
||||||
error: string;
|
error: string;
|
||||||
loadIframe: boolean;
|
loadIframe: boolean;
|
||||||
minimized: boolean;
|
minimized: boolean;
|
||||||
|
termsAccepted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class HostSignupDialog extends React.PureComponent<IProps, IState> {
|
export default class HostSignupDialog extends React.PureComponent<IProps, IState> {
|
||||||
private iframeRef: React.RefObject<HTMLIFrameElement> = React.createRef();
|
private iframeRef: React.RefObject<HTMLIFrameElement> = React.createRef();
|
||||||
private readonly hostSignupSetupUrl: string;
|
private readonly config: IHostSignupConfig;
|
||||||
|
|
||||||
constructor(props: IProps) {
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -46,13 +53,14 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
error: null,
|
error: null,
|
||||||
loadIframe: false,
|
loadIframe: false,
|
||||||
minimized: false,
|
minimized: false,
|
||||||
|
termsAccepted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.hostSignupSetupUrl = SdkConfig.get().host_signup.url;
|
this.config = SdkConfig.get().hostSignup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private messageHandler = async (message: IPostmessage) => {
|
private messageHandler = async (message: IPostmessage) => {
|
||||||
if (!this.hostSignupSetupUrl.startsWith(message.origin)) {
|
if (!this.config.url.startsWith(message.origin)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (message.data.action) {
|
switch (message.data.action) {
|
||||||
|
@ -73,15 +81,17 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case PostmessageAction.CloseDialog:
|
case PostmessageAction.CloseDialog:
|
||||||
return this.onFinished(true);
|
return this.closeDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private maximizeDialog = () => {
|
private maximizeDialog = () => {
|
||||||
|
if (this.state.minimized) {
|
||||||
this.setState({
|
this.setState({
|
||||||
minimized: false,
|
minimized: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private minimizeDialog = () => {
|
private minimizeDialog = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -97,8 +107,8 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
return HostSignupStore.instance.setHostSignupActive(false);
|
return HostSignupStore.instance.setHostSignupActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onFinished = async (result: boolean) => {
|
private onCloseClick = async () => {
|
||||||
if (result || this.state.completed) {
|
if (this.state.completed) {
|
||||||
// We're done, close
|
// We're done, close
|
||||||
return this.closeDialog();
|
return this.closeDialog();
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,7 +131,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
}
|
}
|
||||||
|
|
||||||
private sendMessage = (message: IPostmessageResponseData) => {
|
private sendMessage = (message: IPostmessageResponseData) => {
|
||||||
this.iframeRef.current.contentWindow.postMessage(message, this.hostSignupSetupUrl);
|
this.iframeRef.current.contentWindow.postMessage(message, this.config.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendAccountDetails() {
|
private async sendAccountDetails() {
|
||||||
|
@ -141,6 +151,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
openIdToken: openIdToken.access_token,
|
openIdToken: openIdToken.access_token,
|
||||||
serverName: await MatrixClientPeg.get().getDomain(),
|
serverName: await MatrixClientPeg.get().getDomain(),
|
||||||
userLocalpart: await MatrixClientPeg.get().getUserIdLocalpart(),
|
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() {
|
public componentWillUnmount() {
|
||||||
if (HostSignupStore.instance.isHostSignupActive) {
|
if (HostSignupStore.instance.isHostSignupActive) {
|
||||||
// Run the close dialog actions if we're still active, otherwise good to go
|
// 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">
|
<div className="mx_HostSignup_persisted">
|
||||||
<PersistedElement key="host_signup" persistKey="host_signup">
|
<PersistedElement key="host_signup" persistKey="host_signup">
|
||||||
<div className={this.state.minimized ? "" : "mx_Dialog_wrapper"}>
|
<div className={this.state.minimized ? "" : "mx_Dialog_wrapper"}>
|
||||||
<div className={
|
<div className={["mx_Dialog",
|
||||||
this.state.minimized ? "mx_HostSignupDialog_minimized" : "mx_HostSignupDialog mx_Dialog"
|
this.state.minimized ? "mx_HostSignupDialog_minimized" : "mx_HostSignupDialog"].join(" ")
|
||||||
}>
|
}>
|
||||||
{this.state.loadIframe &&
|
{this.state.loadIframe &&
|
||||||
|
<>
|
||||||
|
{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
|
<iframe
|
||||||
src={this.hostSignupSetupUrl}
|
src={this.config.url}
|
||||||
ref={this.iframeRef}
|
ref={this.iframeRef}
|
||||||
sandbox="allow-forms allow-scripts allow-same-origin"
|
sandbox="allow-forms allow-scripts allow-same-origin"
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
{!this.state.loadIframe &&
|
{!this.state.loadIframe &&
|
||||||
<div className="mx_HostSignupDialog_info">
|
<div className="mx_HostSignupDialog_info">
|
||||||
{this.state.minimized &&
|
{this.config.info.image &&
|
||||||
<button onClick={this.maximizeDialog}>Maximize</button>
|
|
||||||
}
|
|
||||||
<img
|
<img
|
||||||
alt="image of planet"
|
alt={this.config.info.image.alt}
|
||||||
src={require("../../../../res/img/host_signup.png")}
|
src={this.config.info.image.src}
|
||||||
/>
|
/>
|
||||||
<div className="mx_HostSignupDialog_content">
|
}
|
||||||
<h1>Unlock the power of Element</h1>
|
<div className="mx_HostSignupDialog_content_top">
|
||||||
<p>
|
<h1 className="mx_HostSignupDialog_text_dark">
|
||||||
Congratulations! You taken your first steps into unlocking the full
|
{this.config.info.title}
|
||||||
power of the Element app. In a few minutes, you'll be able to
|
</h1>
|
||||||
see how powerful our
|
{this.config.info.additionalParagraphs &&
|
||||||
Matrix services are and take control of your conversation data.
|
<div className="mx_HostSignupDialog_paragraphs">
|
||||||
</p>
|
{this.config.info.additionalParagraphs.map((para, index) => {
|
||||||
|
return <p className="mx_HostSignupDialog_text_light" key={index}>
|
||||||
|
{para}
|
||||||
|
</p>;
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
}
|
||||||
<button onClick={this.closeDialog}>Maybe later</button>
|
{this.config.info.additionalInfoLink &&
|
||||||
<button onClick={this.loadIframe} className="mx_Dialog_primary">
|
<p><small>
|
||||||
Lets get started
|
<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 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>
|
||||||
<button onClick={this.minimizeDialog}>Minimize</button>
|
|
||||||
</div>
|
</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>
|
</div>
|
||||||
}
|
}
|
||||||
{this.state.error &&
|
{this.state.error &&
|
||||||
|
@ -208,7 +289,7 @@ export default class HostSignupDialog extends React.PureComponent<IProps, IState
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{!this.state.minimized &&
|
{!this.state.minimized &&
|
||||||
<div className="mx_Dialog_background" />
|
<div className="mx_Dialog_background mx_HostSignupDialog_background" />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</PersistedElement>
|
</PersistedElement>
|
||||||
|
|
|
@ -29,6 +29,7 @@ interface IAccountData {
|
||||||
openIdToken: string;
|
openIdToken: string;
|
||||||
serverName: string;
|
serverName: string;
|
||||||
userLocalpart: string;
|
userLocalpart: string;
|
||||||
|
termsAccepted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPostmessageRequestData {
|
export interface IPostmessageRequestData {
|
||||||
|
@ -44,3 +45,43 @@ export interface IPostmessage {
|
||||||
data: IPostmessageRequestData;
|
data: IPostmessageRequestData;
|
||||||
origin: string;
|
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