2019-07-09 20:51:56 +03:00
|
|
|
/*
|
|
|
|
Copyright 2019 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 url from 'url';
|
|
|
|
import React from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2019-12-20 04:19:56 +03:00
|
|
|
import * as sdk from '../../../index';
|
2019-07-09 20:51:56 +03:00
|
|
|
import { _t, pickBestLanguage } from '../../../languageHandler';
|
|
|
|
|
|
|
|
import Matrix from 'matrix-js-sdk';
|
2021-03-09 05:59:41 +03:00
|
|
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
2019-07-09 20:51:56 +03:00
|
|
|
|
2019-07-10 16:32:37 +03:00
|
|
|
class TermsCheckbox extends React.PureComponent {
|
2019-07-09 20:51:56 +03:00
|
|
|
static propTypes = {
|
|
|
|
onChange: PropTypes.func.isRequired,
|
|
|
|
url: PropTypes.string.isRequired,
|
|
|
|
checked: PropTypes.bool.isRequired,
|
|
|
|
}
|
|
|
|
|
|
|
|
onChange = (ev) => {
|
|
|
|
this.props.onChange(this.props.url, ev.target.checked);
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
return <input type="checkbox"
|
|
|
|
onChange={this.onChange}
|
|
|
|
checked={this.props.checked}
|
|
|
|
/>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-09 05:59:41 +03:00
|
|
|
@replaceableComponent("views.dialogs.TermsDialog")
|
2019-07-10 16:32:37 +03:00
|
|
|
export default class TermsDialog extends React.PureComponent {
|
2019-07-09 20:51:56 +03:00
|
|
|
static propTypes = {
|
|
|
|
/**
|
2019-07-11 16:46:20 +03:00
|
|
|
* Array of [Service, policies] pairs, where policies is the response from the
|
2019-07-10 17:12:05 +03:00
|
|
|
* /terms endpoint for that service
|
2019-07-09 20:51:56 +03:00
|
|
|
*/
|
2019-07-11 12:53:45 +03:00
|
|
|
policiesAndServicePairs: PropTypes.array.isRequired,
|
|
|
|
|
|
|
|
/**
|
|
|
|
* urls that the user has already agreed to
|
|
|
|
*/
|
|
|
|
agreedUrls: PropTypes.arrayOf(PropTypes.string),
|
2019-07-09 20:51:56 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called with:
|
|
|
|
* * success {bool} True if the user accepted any douments, false if cancelled
|
|
|
|
* * agreedUrls {string[]} List of agreed URLs
|
|
|
|
*/
|
|
|
|
onFinished: PropTypes.func.isRequired,
|
|
|
|
}
|
|
|
|
|
2019-07-11 12:53:45 +03:00
|
|
|
constructor(props) {
|
2019-07-09 20:51:56 +03:00
|
|
|
super();
|
|
|
|
this.state = {
|
|
|
|
// url -> boolean
|
|
|
|
agreedUrls: {},
|
|
|
|
};
|
2019-07-11 12:53:45 +03:00
|
|
|
for (const url of props.agreedUrls) {
|
|
|
|
this.state.agreedUrls[url] = true;
|
|
|
|
}
|
2019-07-09 20:51:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
_onCancelClick = () => {
|
|
|
|
this.props.onFinished(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
_onNextClick = () => {
|
|
|
|
this.props.onFinished(true, Object.keys(this.state.agreedUrls).filter((url) => this.state.agreedUrls[url]));
|
|
|
|
}
|
|
|
|
|
|
|
|
_nameForServiceType(serviceType, host) {
|
|
|
|
switch (serviceType) {
|
2019-07-10 14:08:26 +03:00
|
|
|
case Matrix.SERVICE_TYPES.IS:
|
2019-07-09 20:51:56 +03:00
|
|
|
return <div>{_t("Identity Server")}<br />({host})</div>;
|
2019-07-10 14:08:26 +03:00
|
|
|
case Matrix.SERVICE_TYPES.IM:
|
2019-11-21 06:14:20 +03:00
|
|
|
return <div>{_t("Integration Manager")}<br />({host})</div>;
|
2019-07-09 20:51:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 19:57:10 +03:00
|
|
|
_summaryForServiceType(serviceType) {
|
2019-07-09 20:51:56 +03:00
|
|
|
switch (serviceType) {
|
2019-07-10 14:08:26 +03:00
|
|
|
case Matrix.SERVICE_TYPES.IS:
|
2019-07-09 20:51:56 +03:00
|
|
|
return <div>
|
|
|
|
{_t("Find others by phone or email")}
|
|
|
|
<br />
|
|
|
|
{_t("Be found by phone or email")}
|
|
|
|
</div>;
|
2019-07-10 14:08:26 +03:00
|
|
|
case Matrix.SERVICE_TYPES.IM:
|
2019-07-09 20:51:56 +03:00
|
|
|
return <div>
|
2019-07-10 16:17:42 +03:00
|
|
|
{_t("Use bots, bridges, widgets and sticker packs")}
|
2019-07-09 20:51:56 +03:00
|
|
|
</div>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_onTermsCheckboxChange = (url, checked) => {
|
2019-07-10 17:12:05 +03:00
|
|
|
this.setState({
|
|
|
|
agreedUrls: Object.assign({}, this.state.agreedUrls, { [url]: checked }),
|
|
|
|
});
|
2019-07-09 20:51:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
|
|
|
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
|
|
|
|
|
|
|
const rows = [];
|
2019-07-10 17:12:05 +03:00
|
|
|
for (const policiesAndService of this.props.policiesAndServicePairs) {
|
|
|
|
const parsedBaseUrl = url.parse(policiesAndService.service.baseUrl);
|
2019-07-09 20:51:56 +03:00
|
|
|
|
2019-07-22 14:25:12 +03:00
|
|
|
const policyValues = Object.values(policiesAndService.policies);
|
|
|
|
for (let i = 0; i < policyValues.length; ++i) {
|
|
|
|
const termDoc = policyValues[i];
|
2019-07-09 20:51:56 +03:00
|
|
|
const termsLang = pickBestLanguage(Object.keys(termDoc).filter((k) => k !== 'version'));
|
|
|
|
let serviceName;
|
2019-09-30 19:37:30 +03:00
|
|
|
let summary;
|
2019-07-09 20:51:56 +03:00
|
|
|
if (i === 0) {
|
2019-07-10 17:12:05 +03:00
|
|
|
serviceName = this._nameForServiceType(policiesAndService.service.serviceType, parsedBaseUrl.host);
|
2019-09-30 19:37:30 +03:00
|
|
|
summary = this._summaryForServiceType(
|
|
|
|
policiesAndService.service.serviceType,
|
|
|
|
);
|
2019-07-09 20:51:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
rows.push(<tr key={termDoc[termsLang].url}>
|
|
|
|
<td className="mx_TermsDialog_service">{serviceName}</td>
|
|
|
|
<td className="mx_TermsDialog_summary">{summary}</td>
|
2020-02-24 01:14:29 +03:00
|
|
|
<td>{termDoc[termsLang].name} <a rel="noreferrer noopener" target="_blank" href={termDoc[termsLang].url}>
|
2019-09-27 19:57:10 +03:00
|
|
|
<span className="mx_TermsDialog_link" />
|
2019-07-09 20:51:56 +03:00
|
|
|
</a></td>
|
|
|
|
<td><TermsCheckbox
|
|
|
|
url={termDoc[termsLang].url}
|
|
|
|
onChange={this._onTermsCheckboxChange}
|
|
|
|
checked={Boolean(this.state.agreedUrls[termDoc[termsLang].url])}
|
|
|
|
/></td>
|
|
|
|
</tr>);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if all the documents for at least one service have been checked, we can enable
|
|
|
|
// the submit button
|
|
|
|
let enableSubmit = false;
|
2019-07-10 17:12:05 +03:00
|
|
|
for (const policiesAndService of this.props.policiesAndServicePairs) {
|
2019-07-09 20:51:56 +03:00
|
|
|
let docsAgreedForService = 0;
|
2019-07-10 17:12:05 +03:00
|
|
|
for (const terms of Object.values(policiesAndService.policies)) {
|
2019-07-09 20:51:56 +03:00
|
|
|
let docAgreed = false;
|
|
|
|
for (const lang of Object.keys(terms)) {
|
|
|
|
if (lang === 'version') continue;
|
|
|
|
if (this.state.agreedUrls[terms[lang].url]) {
|
|
|
|
docAgreed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (docAgreed) {
|
|
|
|
++docsAgreedForService;
|
|
|
|
}
|
|
|
|
}
|
2019-07-10 17:12:05 +03:00
|
|
|
if (docsAgreedForService === Object.keys(policiesAndService.policies).length) {
|
2019-07-09 20:51:56 +03:00
|
|
|
enableSubmit = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2019-07-23 17:11:38 +03:00
|
|
|
<BaseDialog
|
2019-07-09 20:51:56 +03:00
|
|
|
fixedWidth={false}
|
|
|
|
onFinished={this._onCancelClick}
|
|
|
|
title={_t("Terms of Service")}
|
|
|
|
contentId='mx_Dialog_content'
|
|
|
|
hasCancel={false}
|
|
|
|
>
|
|
|
|
<div id='mx_Dialog_content'>
|
2019-09-26 20:03:12 +03:00
|
|
|
<p>{_t("To continue you need to accept the terms of this service.")}</p>
|
2019-07-09 20:51:56 +03:00
|
|
|
|
|
|
|
<table className="mx_TermsDialog_termsTable"><tbody>
|
|
|
|
<tr className="mx_TermsDialog_termsTableHeader">
|
|
|
|
<th>{_t("Service")}</th>
|
2019-07-10 16:30:48 +03:00
|
|
|
<th>{_t("Summary")}</th>
|
2019-09-27 19:43:04 +03:00
|
|
|
<th>{_t("Document")}</th>
|
2019-07-09 20:51:56 +03:00
|
|
|
<th>{_t("Accept")}</th>
|
|
|
|
</tr>
|
|
|
|
{rows}
|
|
|
|
</tbody></table>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<DialogButtons primaryButton={_t('Next')}
|
|
|
|
hasCancel={true}
|
|
|
|
onCancel={this._onCancelClick}
|
|
|
|
onPrimaryButtonClick={this._onNextClick}
|
|
|
|
primaryDisabled={!enableSubmit}
|
|
|
|
/>
|
|
|
|
</BaseDialog>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|