Convert things to Typescript and re-use a generic component

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-05-22 13:29:53 +01:00
parent b21e5ba10b
commit 14cee41360
9 changed files with 342 additions and 303 deletions

View file

@ -1,56 +0,0 @@
/*
Copyright 2020 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 PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import dis from "../../../dispatcher/dispatcher";
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import DeviceListener from '../../../DeviceListener';
import FormButton from '../elements/FormButton';
import { replaceableComponent } from '../../../utils/replaceableComponent';
@replaceableComponent("views.toasts.BulkUnverifiedSessionsToast")
export default class BulkUnverifiedSessionsToast extends React.PureComponent {
static propTypes = {
deviceIds: PropTypes.array,
}
_onLaterClick = () => {
DeviceListener.sharedInstance().dismissUnverifiedSessions(this.props.deviceIds);
};
_onReviewClick = async () => {
DeviceListener.sharedInstance().dismissUnverifiedSessions(this.props.deviceIds);
dis.dispatch({
action: 'view_user_info',
userId: MatrixClientPeg.get().getUserId(),
});
};
render() {
return (<div>
<div className="mx_Toast_description">
{_t("Verify all your sessions to ensure your account & messages are safe")}
</div>
<div className="mx_Toast_buttons" aria-live="off">
<FormButton label={_t("Later")} kind="danger" onClick={this._onLaterClick} />
<FormButton label={_t("Review")} onClick={this._onReviewClick} />
</div>
</div>);
}
}

View file

@ -0,0 +1,42 @@
/*
Copyright 2020 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, {ReactChild} from "react";
import FormButton from "../elements/FormButton";
interface IProps {
description: ReactChild;
acceptLabel: string;
rejectLabel?: string;
onAccept();
onReject?();
}
const GenericToast: React.FC<IProps> = ({description, acceptLabel, rejectLabel, onAccept, onReject}) => {
return <div>
<div className="mx_Toast_description">
{ description }
</div>
<div className="mx_Toast_buttons" aria-live="off">
{onReject && rejectLabel && <FormButton label={rejectLabel} kind="danger" onClick={onReject} /> }
<FormButton label={acceptLabel} onClick={onAccept} />
</div>
</div>;
};
export default GenericToast;

View file

@ -1,88 +0,0 @@
/*
Copyright 2020 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 PropTypes from 'prop-types';
import Modal from '../../../Modal';
import * as sdk from "../../../index";
import { _t } from '../../../languageHandler';
import DeviceListener from '../../../DeviceListener';
import SetupEncryptionDialog from "../dialogs/SetupEncryptionDialog";
import { accessSecretStorage } from '../../../CrossSigningManager';
export default class SetupEncryptionToast extends React.PureComponent {
static propTypes = {
toastKey: PropTypes.string.isRequired,
kind: PropTypes.oneOf([
'set_up_encryption',
'verify_this_session',
'upgrade_encryption',
]).isRequired,
};
_onLaterClick = () => {
DeviceListener.sharedInstance().dismissEncryptionSetup();
};
_onSetupClick = async () => {
if (this.props.kind === "verify_this_session") {
Modal.createTrackedDialog('Verify session', 'Verify session', SetupEncryptionDialog,
{}, null, /* priority = */ false, /* static = */ true);
} else {
const Spinner = sdk.getComponent("elements.Spinner");
const modal = Modal.createDialog(
Spinner, null, 'mx_Dialog_spinner', /* priority */ false, /* static */ true,
);
try {
await accessSecretStorage();
} finally {
modal.close();
}
}
};
getDescription() {
switch (this.props.kind) {
case 'set_up_encryption':
case 'upgrade_encryption':
return _t('Verify yourself & others to keep your chats safe');
case 'verify_this_session':
return _t('Other users may not trust it');
}
}
getSetupCaption() {
switch (this.props.kind) {
case 'set_up_encryption':
return _t('Set up');
case 'upgrade_encryption':
return _t('Upgrade');
case 'verify_this_session':
return _t('Verify');
}
}
render() {
const FormButton = sdk.getComponent("elements.FormButton");
return (<div>
<div className="mx_Toast_description">{this.getDescription()}</div>
<div className="mx_Toast_buttons" aria-live="off">
<FormButton label={_t("Later")} kind="danger" onClick={this._onLaterClick} />
<FormButton label={this.getSetupCaption()} onClick={this._onSetupClick} />
</div>
</div>);
}
}

View file

@ -1,66 +0,0 @@
/*
Copyright 2020 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 PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import Modal from '../../../Modal';
import DeviceListener from '../../../DeviceListener';
import NewSessionReviewDialog from '../dialogs/NewSessionReviewDialog';
import FormButton from '../elements/FormButton';
import { replaceableComponent } from '../../../utils/replaceableComponent';
@replaceableComponent("views.toasts.UnverifiedSessionToast")
export default class UnverifiedSessionToast extends React.PureComponent {
static propTypes = {
deviceId: PropTypes.string,
}
_onLaterClick = () => {
DeviceListener.sharedInstance().dismissUnverifiedSessions([this.props.deviceId]);
};
_onReviewClick = async () => {
const cli = MatrixClientPeg.get();
Modal.createTrackedDialog('New Session Review', 'Starting dialog', NewSessionReviewDialog, {
userId: cli.getUserId(),
device: cli.getStoredDevice(cli.getUserId(), this.props.deviceId),
onFinished: (r) => {
if (!r) {
/* This'll come back false if the user clicks "this wasn't me" and saw a warning dialog */
DeviceListener.sharedInstance().dismissUnverifiedSessions([this.props.deviceId]);
}
},
}, null, /* priority = */ false, /* static = */ true);
};
render() {
const cli = MatrixClientPeg.get();
const device = cli.getStoredDevice(cli.getUserId(), this.props.deviceId);
return (<div>
<div className="mx_Toast_description">
{_t(
"Verify the new login accessing your account: %(name)s", { name: device.getDisplayName()})}
</div>
<div className="mx_Toast_buttons" aria-live="off">
<FormButton label={_t("Later")} kind="danger" onClick={this._onLaterClick} />
<FormButton label={_t("Verify")} onClick={this._onReviewClick} />
</div>
</div>);
}
}

View file

@ -14,8 +14,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import PropTypes from 'prop-types';
import React from "react";
import * as sdk from "../../../index";
import { _t } from '../../../languageHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
@ -24,8 +24,23 @@ import {userLabelForEventRoom} from "../../../utils/KeyVerificationStateObserver
import dis from "../../../dispatcher/dispatcher";
import ToastStore from "../../../stores/ToastStore";
import Modal from "../../../Modal";
import GenericToast from "./GenericToast";
import {VerificationRequest} from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import {DeviceInfo} from "matrix-js-sdk/src/crypto/deviceinfo";
interface IProps {
toastKey: string;
request: VerificationRequest;
}
interface IState {
counter: number;
device?: DeviceInfo;
}
export default class VerificationRequestToast extends React.PureComponent<IProps, IState> {
private intervalHandle: NodeJS.Timeout;
export default class VerificationRequestToast extends React.PureComponent {
constructor(props) {
super(props);
this.state = {counter: Math.ceil(props.request.timeout / 1000)};
@ -34,7 +49,7 @@ export default class VerificationRequestToast extends React.PureComponent {
async componentDidMount() {
const {request} = this.props;
if (request.timeout && request.timeout > 0) {
this._intervalHandle = setInterval(() => {
this.intervalHandle = setInterval(() => {
let {counter} = this.state;
counter = Math.max(0, counter - 1);
this.setState({counter});
@ -56,7 +71,7 @@ export default class VerificationRequestToast extends React.PureComponent {
}
componentWillUnmount() {
clearInterval(this._intervalHandle);
clearInterval(this.intervalHandle);
const {request} = this.props;
request.off("change", this._checkRequestIsPending);
}
@ -110,7 +125,6 @@ export default class VerificationRequestToast extends React.PureComponent {
};
render() {
const FormButton = sdk.getComponent("elements.FormButton");
const {request} = this.props;
let nameLabel;
if (request.isSelfVerification) {
@ -133,20 +147,16 @@ export default class VerificationRequestToast extends React.PureComponent {
}
}
}
const declineLabel = this.state.counter == 0 ?
const declineLabel = this.state.counter === 0 ?
_t("Decline") :
_t("Decline (%(counter)s)", {counter: this.state.counter});
return (<div>
<div className="mx_Toast_description">{nameLabel}</div>
<div className="mx_Toast_buttons" aria-live="off">
<FormButton label={declineLabel} kind="danger" onClick={this.cancel} />
<FormButton label={_t("Accept")} onClick={this.accept} />
</div>
</div>);
return <GenericToast
description={nameLabel}
acceptLabel={_t("Accept")}
onAccept={this.accept}
rejectLabel={declineLabel}
onReject={this.cancel}
/>;
}
}
VerificationRequestToast.propTypes = {
request: PropTypes.object.isRequired,
toastKey: PropTypes.string.isRequired,
};