merge next
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Erfolgreich bestätigt",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "Passwort erfolgreich zurückgesetzt",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmed successfully",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "Password reset successfully",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmado con éxito",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "Restablecimiento de contraseña con éxito",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
},
|
||||
"cred_confirmed_successfully": {
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated."
|
||||
"description": "Notification message that the credential was successfully validated."
|
||||
},
|
||||
"credential_email_prompt": {
|
||||
"defaultMessage": "Your registration email",
|
||||
@@ -708,6 +708,10 @@
|
||||
"defaultMessage": "A text message with security code has been sent.",
|
||||
"description": "Notification that the SMS with password reset instructions has been sent"
|
||||
},
|
||||
"password_reset_success": {
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset."
|
||||
},
|
||||
"password_unchanged_prompt": {
|
||||
"defaultMessage": "Unchanged",
|
||||
"description": "Message in editor while password is unchanged"
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmé avec succès",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "Mot de passe réinitialisé avec succès",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "성공적으로 확인됨",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "비밀번호 재설정 성공",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Confirmat cu succes",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "Resetarea parolei cu succes",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "Подтверждено успешно",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "Пароль успешно изменен",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "確認成功",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "密碼重置成功",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -1420,7 +1420,7 @@
|
||||
"cred_confirmed_successfully": {
|
||||
"translation": "确认成功",
|
||||
"defaultMessage": "Confirmed successfully",
|
||||
"description": "Message explaining that the credential was successfully validated.",
|
||||
"description": "Notification message that the credential was successfully validated.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
@@ -1654,5 +1654,12 @@
|
||||
"description": "Conference call label",
|
||||
"missing": true,
|
||||
"obsolete": false
|
||||
},
|
||||
"password_reset_success": {
|
||||
"translation": "密码重置成功",
|
||||
"defaultMessage": "Password reset successfully",
|
||||
"description": "Notification message that the password was successfully reset.",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ function handleImageData(el, data, attr) {
|
||||
return el;
|
||||
}
|
||||
|
||||
// Additional processing of image data.
|
||||
// Additional processing of attached video data.
|
||||
function handleVideoData(el, data, attr) {
|
||||
if (!data) {
|
||||
attr.src = 'img/broken_video.png';
|
||||
@@ -241,7 +241,7 @@ function handleVideoData(el, data, attr) {
|
||||
}
|
||||
el = InlineVideo;
|
||||
} else {
|
||||
// Use custom element instead of <img>.
|
||||
// Use custom element instead of <img> or <video>.
|
||||
el = UploadingImage;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ export default class HashNavigation {
|
||||
// Parse hash as in http://www.example.com/path#hash as if it were
|
||||
// path and arguments.
|
||||
static parseUrlHash(hash) {
|
||||
// Split path from args, path -> parts[0], args->path[1]
|
||||
// Split 'path/?args' into 'path/' and 'args', path -> parts[0], args->path[1].
|
||||
const parts = hash.split('?', 2);
|
||||
const params = {};
|
||||
let path = [];
|
||||
@@ -32,7 +32,9 @@ export default class HashNavigation {
|
||||
const args = [];
|
||||
for (const key in params) {
|
||||
if (params.hasOwnProperty(key)) {
|
||||
args.push(key + '=' + encodeURIComponent(params[key]));
|
||||
if (params[key] !== undefined) {
|
||||
args.push(key + '=' + encodeURIComponent(params[key]));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args.length > 0) {
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
// This is a generated file. Don't edit.
|
||||
|
||||
export const PACKAGE_VERSION = "0.23.0-rc1";
|
||||
export const PACKAGE_VERSION = "0.23.0-rc2";
|
||||
|
||||
@@ -46,12 +46,21 @@ export default class AccountSettingsView extends React.Component {
|
||||
val={this.state.credEdit.val}
|
||||
done={this.state.credEdit.done}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onSubmit={this.props.onCredAdd}
|
||||
onCredAdd={this.props.onCredAdd}
|
||||
onCredConfirm={this.props.onCredConfirm}
|
||||
onCancel={_ => this.setState({credEdit: undefined})}
|
||||
onError={this.props.onError} />
|
||||
);
|
||||
}
|
||||
|
||||
// Count how many times each method is validated.
|
||||
const validated = {};
|
||||
this.state.credentials.forEach(cred => {
|
||||
if (cred.done) {
|
||||
validated[cred.meth] = (validated[cred.meth] || 0) + 1;
|
||||
}
|
||||
});
|
||||
|
||||
const credentials = [];
|
||||
this.state.credentials.forEach((cred, idx) => {
|
||||
if (!['email', 'tel'].includes(cred.meth)) {
|
||||
@@ -68,15 +77,14 @@ export default class AccountSettingsView extends React.Component {
|
||||
credentials.push(
|
||||
<div className="group quoted" key={idx}>
|
||||
<tt className="clickable" onClick={e => {e.preventDefault(); this.setState({credEdit: cred});}}>{val}</tt>
|
||||
<span> {
|
||||
cred.done ? null :
|
||||
<>
|
||||
<i className="material-icons">pending</i>
|
||||
<span> {cred.done ? null : <i className="material-icons">pending</i>}
|
||||
{!cred.done || validated[cred.meth] > 1 || this.props.reqCredMethod != cred.meth ?
|
||||
<a href="#" onClick={e => {e.preventDefault(); this.props.onCredDelete(cred.meth, cred.val);}}>
|
||||
<i className="material-icons">delete</i>
|
||||
</a>
|
||||
</>
|
||||
}</span>
|
||||
:
|
||||
null}
|
||||
</span>
|
||||
</div>);
|
||||
});
|
||||
if (credentials.length > 0) {
|
||||
|
||||
@@ -186,16 +186,23 @@ class MessagesView extends React.Component {
|
||||
|
||||
getVisibleMessageRange(holderRect) {
|
||||
let min = Number.MAX_SAFE_INTEGER, max = -1;
|
||||
this.chatMessageRefs.forEach((ref, seq) => {
|
||||
let visibilityStatus = false;
|
||||
this.chatMessageRefs.every((ref, seq) => {
|
||||
if (ref.current) {
|
||||
const { top, bottom, height } = ref.current.getBoundingClientRect();
|
||||
const visible = top <= holderRect.top ? holderRect.top - top <= height : bottom - holderRect.bottom <= height;
|
||||
if (visible) {
|
||||
visibilityStatus = true;
|
||||
min = Math.min(min, seq);
|
||||
max = Math.max(max, seq);
|
||||
} else if (visibilityStatus) {
|
||||
// The remaining elements are no longer visible, no need to iterate them.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return max >= min ? {min: min, max: max} : {min: 0, max: 0};
|
||||
}
|
||||
|
||||
@@ -274,12 +281,12 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
|
||||
if (topic) {
|
||||
if ((this.state.topic != prevState.topic) || !prevProps.ready) {
|
||||
if ((this.state.topic != prevState.topic) || (this.props.myUserId && !prevProps.myUserId)) {
|
||||
// Don't immediately subscribe to a new p2p topic, wait for the first message.
|
||||
const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);
|
||||
if (topic.isP2PType() && newTopic && !IMMEDIATE_P2P_SUBSCRIPTION) {
|
||||
topic.getMeta(topic.startMetaQuery().withDesc().build());
|
||||
} else {
|
||||
} else if (this.props.myUserId) {
|
||||
this.subscribe(topic);
|
||||
}
|
||||
} else if (topic.isSubscribed() && this.state.isReader && !prevState.isReader) {
|
||||
@@ -321,7 +328,8 @@ class MessagesView extends React.Component {
|
||||
showGoToLastButton: false,
|
||||
dragging: false,
|
||||
pins: [],
|
||||
selectedPin: 0
|
||||
selectedPin: 0,
|
||||
subsVersion: 0
|
||||
};
|
||||
} else if (nextProps.topic != prevState.topic) {
|
||||
const topic = nextProps.tinode.getTopic(nextProps.topic);
|
||||
@@ -478,7 +486,6 @@ class MessagesView extends React.Component {
|
||||
|
||||
// Is this a new topic?
|
||||
const newTopic = (this.props.newTopicParams && this.props.newTopicParams._topicName == this.props.topic);
|
||||
|
||||
// Don't request the tags. They are useless unless the user
|
||||
// is the owner and is editing the topic.
|
||||
let getQuery = topic.startMetaQuery().withLaterDesc().withLaterSub().withAux();
|
||||
@@ -503,6 +510,9 @@ class MessagesView extends React.Component {
|
||||
if (this.state.topic != ctrl.topic) {
|
||||
this.setState({topic: ctrl.topic});
|
||||
}
|
||||
if (this.state.deleted) {
|
||||
this.setState({deleted: false});
|
||||
}
|
||||
this.props.onNewTopicCreated(this.props.topic, ctrl.topic);
|
||||
// If there are unsent messages (except hard-failed and video call messages),
|
||||
// try sending them now. Hard-failed and unsent video call messages will be dropped.
|
||||
@@ -576,13 +586,14 @@ class MessagesView extends React.Component {
|
||||
showGoToLastButton: (pos > SHOW_GO_TO_LAST_DIST) && (pos < this.state.scrollPosition),
|
||||
});
|
||||
|
||||
if (this.state.fetchingMessages) {
|
||||
if (this.state.fetchingMessages || this.processingScrollEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.target.scrollTop <= FETCH_PAGE_TRIGGER) {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
if (topic && topic.isSubscribed()) {
|
||||
this.processingScrollEvent = true;
|
||||
const {min, max} = this.getVisibleMessageRange(event.target.getBoundingClientRect());
|
||||
const gaps = topic.msgHasMoreMessages(min, max, false);
|
||||
if (gaps.length > 0) {
|
||||
@@ -594,6 +605,7 @@ class MessagesView extends React.Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.processingScrollEvent = false;
|
||||
}
|
||||
|
||||
/* Mount drag and drop events */
|
||||
@@ -705,12 +717,12 @@ class MessagesView extends React.Component {
|
||||
if (this.state.topic) {
|
||||
const subs = [];
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
topic.subscribers((sub) => {
|
||||
topic.subscribers(sub => {
|
||||
if (sub.online && sub.user != this.props.myUserId) {
|
||||
subs.push(sub);
|
||||
}
|
||||
});
|
||||
const newState = {onlineSubs: subs};
|
||||
const newState = {onlineSubs: subs, subsVersion: this.state.subsVersion + 1};
|
||||
const peer = topic.p2pPeerDesc();
|
||||
if (peer) {
|
||||
Object.assign(newState, {
|
||||
|
||||
@@ -48,7 +48,23 @@ class PasswordResetView extends React.PureComponent {
|
||||
|
||||
componentDidMount() {
|
||||
const parsed = HashNavigation.parseUrlHash(window.location.hash);
|
||||
this.setState({token: parsed.params.token, scheme: parsed.params.scheme});
|
||||
const newState = {
|
||||
token: parsed.params.token,
|
||||
scheme: parsed.params.scheme,
|
||||
code: parsed.params.code || ''
|
||||
}
|
||||
|
||||
this.savedCred = parsed.params.cred;
|
||||
if (this.props.reqCredMethod && parsed.params.cred) {
|
||||
newState[this.props.reqCredMethod] = this.savedCred;
|
||||
}
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps.reqCredMethod != this.props.reqCredMethod && this.props.reqCredMethod) {
|
||||
this.setState({[this.props.reqCredMethod]: this.savedCred || ''});
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit(e) {
|
||||
@@ -57,12 +73,12 @@ class PasswordResetView extends React.PureComponent {
|
||||
// Reset using token.
|
||||
this.props.onReset(this.state.password.trim(), {
|
||||
scheme: 'token',
|
||||
token: this.state.token
|
||||
secret: this.state.token
|
||||
});
|
||||
} else if (this.state.code && this.props.reqCredMethod) {
|
||||
// Reset using security code.
|
||||
// The secret is structured as <code>:<cred_method>:<cred_value>, "123456:email:alice@example.com".
|
||||
const cred = this.state.email.trim() || this.state.tel.trim();
|
||||
const cred = this.props.reqCredMethod == 'email' ? this.state.email.trim() : this.state.tel.trim();
|
||||
this.props.onReset(this.state.password.trim(), {
|
||||
scheme: 'code',
|
||||
secret: btoa(`${this.state.code}:${this.props.reqCredMethod}:${cred}`)
|
||||
@@ -102,7 +118,7 @@ class PasswordResetView extends React.PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const showCredentialInput = !(this.state.token && this.state.scheme);
|
||||
const showCredentialInput = !((this.state.token || (this.state.code && this.props.reqCredMethod)) && this.state.scheme);
|
||||
const showPasswordInput = !showCredentialInput || this.state.haveCode || this.state.sent;
|
||||
|
||||
const passwordInput = (<>
|
||||
@@ -193,7 +209,7 @@ class PasswordResetView extends React.PureComponent {
|
||||
{this.state.haveCode || this.state.sent ? codeInput : null}
|
||||
{showPasswordInput ? passwordInput : null}
|
||||
<div className="dialog-buttons">
|
||||
{this.state.haveCode || this.state.sent ? null :
|
||||
{this.state.haveCode || this.state.sent || this.state.token || this.state.code ? null :
|
||||
<a href="#" onClick={this.handleShowCodeField} style={{marginRight: 'auto'}}>
|
||||
<FormattedMessage id="password_i_have_code" defaultMessage="I have code"
|
||||
description="Call to open field to enter password reset code" />
|
||||
|
||||
@@ -181,6 +181,7 @@ class SidepanelView extends React.PureComponent {
|
||||
tinode={this.props.tinode}
|
||||
myUserId={this.props.myUserId}
|
||||
trustedBadges={this.props.trustedBadges}
|
||||
reqCredMethod={this.props.reqCredMethod}
|
||||
onShowCountrySelector={this.props.onShowCountrySelector}
|
||||
onNavigate={this.props.onNavigate}
|
||||
onCredAdd={this.props.onCredAdd}
|
||||
|
||||
@@ -83,7 +83,12 @@ const messages = defineMessages({
|
||||
cred_confirmed_successfully: {
|
||||
id: 'cred_confirmed_successfully',
|
||||
defaultMessage: 'Confirmed successfully',
|
||||
description: 'Message explaining that the credential was successfully validated.'
|
||||
description: 'Notification message that the credential was successfully validated.'
|
||||
},
|
||||
password_reset_success: {
|
||||
id: 'password_reset_success',
|
||||
defaultMessage: 'Password reset successfully',
|
||||
description: 'Notification message that the password was successfully reset.'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -763,6 +768,7 @@ class TinodeWeb extends React.Component {
|
||||
parsed.path[0] = 'cred';
|
||||
parsed.params['method'] = params.cred[0];
|
||||
parsed.params['token'] = params.token;
|
||||
parsed.params['code'] = params.code;
|
||||
HashNavigation.navigateTo(HashNavigation.composeUrlHash(parsed.path, parsed.params));
|
||||
}
|
||||
|
||||
@@ -848,7 +854,7 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
} else if (what == 'read') {
|
||||
this.resetContactList();
|
||||
} else if (what == 'msg') {
|
||||
} else if (what == 'msg' && cont) {
|
||||
// Check if the topic is archived. If so, don't play a sound.
|
||||
const topic = this.tinode.getTopic(cont.topic);
|
||||
const archived = topic && topic.isArchived();
|
||||
@@ -887,7 +893,7 @@ class TinodeWeb extends React.Component {
|
||||
} else {
|
||||
// TODO(gene): handle other types of notifications:
|
||||
// * ua -- user agent changes (maybe display a pictogram for mobile/desktop).
|
||||
console.info("Unsupported (yet) presence update:", what, "in", cont.topic);
|
||||
console.info("Unsupported (yet) presence update:", what, "in", (cont || {}).topic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1019,6 +1025,7 @@ class TinodeWeb extends React.Component {
|
||||
} else {
|
||||
// Currently selected contact deleted
|
||||
this.setState({
|
||||
topicSelected: null,
|
||||
errorText: '',
|
||||
errorLevel: null,
|
||||
mobilePanel: 'sidepanel',
|
||||
@@ -1287,7 +1294,7 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
|
||||
handleCredConfirm(method, response) {
|
||||
TinodeWeb.navigateToCredentialsView({cred: [method]});
|
||||
TinodeWeb.navigateToCredentialsView({cred: [method], code: response});
|
||||
}
|
||||
|
||||
// User clicked Cancel button in Setting or Sign Up panel.
|
||||
@@ -1709,6 +1716,7 @@ class TinodeWeb extends React.Component {
|
||||
if (this.tinode.isAuthenticated()) {
|
||||
// Adding new email or phone number in account setting.
|
||||
this.tinode.getMeTopic().setMeta({cred: {meth: cred, resp: code}})
|
||||
.then(_ => HashNavigation.navigateTo(HashNavigation.setUrlSidePanel(window.location.hash, 'contacts')))
|
||||
.catch(err => this.handleError(err.message, 'err'));
|
||||
} else {
|
||||
// Credential validation on signup.
|
||||
@@ -1734,9 +1742,11 @@ class TinodeWeb extends React.Component {
|
||||
} else {
|
||||
this.tinode.connect()
|
||||
.then(_ => this.tinode.updateAccountBasic(null, null, newPassword, {scheme: tempAuth.scheme, secret: secret}))
|
||||
.then(_ => HashNavigation.navigateTo(''))
|
||||
.then(_ => {
|
||||
this.handleError(this.props.intl.formatMessage(messages.password_reset_success), 'info');
|
||||
HashNavigation.navigateTo('');
|
||||
})
|
||||
.catch(err => {
|
||||
// Socket error
|
||||
this.handleError(err.message, 'err');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ class ValidationView extends React.PureComponent {
|
||||
(numbers_only) => <input type="text" id="enter-confirmation-code"
|
||||
placeholder={numbers_only}
|
||||
value={this.state.code} onChange={this.handleCodeChange}
|
||||
onKeyPress={this.handleKeyPress} required />
|
||||
onKeyDown={this.handleKeyPress} required />
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<div className="dialog-buttons">
|
||||
|
||||
@@ -58,8 +58,11 @@ class CredentialEdit extends React.PureComponent {
|
||||
handleSubmit(e) {
|
||||
e.preventDefault();
|
||||
const value = this.props.method == 'email' ? this.state.email : this.state.tel;
|
||||
if (value) {
|
||||
this.props.onSubmit(this.props.method, value);
|
||||
if (this.state.code) {
|
||||
this.props.onError(null);
|
||||
this.props.onCredConfirm(this.props.method, this.state.code);
|
||||
} else if (value) {
|
||||
this.props.onCredAdd(this.props.method, value);
|
||||
this.setState({sent: true});
|
||||
const msg = this.props.method == 'email' ? messages.password_reset_email_sent : messages.password_reset_sms_sent;
|
||||
this.props.onError(this.props.intl.formatMessage(msg), 'info');
|
||||
@@ -68,8 +71,8 @@ class CredentialEdit extends React.PureComponent {
|
||||
|
||||
render() {
|
||||
const readyForCode = this.state.sent || !this.props.done;
|
||||
const currentValue = CredentialEdit.formatPhoneNumber(readyForCode ?
|
||||
(this.state.tel || this.state.email) : this.props.val);
|
||||
const rawValue = readyForCode ? (this.state.tel || this.state.email) : this.props.val;
|
||||
const formattedValue = this.props.method == 'tel' ? CredentialEdit.formatPhoneNumber(rawValue) : rawValue;
|
||||
|
||||
const changeEmail = (
|
||||
<><div className="panel-form-row">
|
||||
@@ -140,21 +143,19 @@ class CredentialEdit extends React.PureComponent {
|
||||
);
|
||||
|
||||
return (<form className="panel-form-column" onSubmit={this.handleSubmit}>
|
||||
{readyForCode ? null :
|
||||
this.props.method == 'email' ?
|
||||
changeEmail
|
||||
: this.props.method == 'tel' ?
|
||||
changePhone
|
||||
: null}
|
||||
{readyForCode ?
|
||||
(this.props.method == 'email' ? newEmailLabel : this.props.method == 'tel' ? newPhoneLabel : null)
|
||||
:
|
||||
(this.props.method == 'email' ? changeEmail : this.props.method == 'tel' ? changePhone : null)
|
||||
}
|
||||
<div className="panel-form-row">
|
||||
<tt className="quoted">{currentValue}</tt>
|
||||
<tt className="quoted">{formattedValue}</tt>
|
||||
</div>
|
||||
{readyForCode ? null :
|
||||
this.props.method == 'email' ?
|
||||
newEmailInput
|
||||
: this.props.method == 'tel' ?
|
||||
newPhoneInput
|
||||
: null}
|
||||
{readyForCode ?
|
||||
null
|
||||
:
|
||||
(this.props.method == 'email' ? newEmailInput : this.props.method == 'tel' ? newPhoneInput : null)
|
||||
}
|
||||
{readyForCode ? codeInput : null}
|
||||
<div className="dialog-buttons">
|
||||
<button className="secondary" onClick={this.props.onCancel}>
|
||||
|
||||
@@ -39,7 +39,7 @@ export default class ErrorPanel extends React.PureComponent {
|
||||
{this.props.text}
|
||||
{this.props.action ?
|
||||
<>
|
||||
 <a href="#"
|
||||
 <a href="#"
|
||||
style={{ whiteSpace: 'nowrap' }}
|
||||
onClick={(e) => {e.preventDefault(); this.props.action();}}>
|
||||
{this.props.actionText}
|
||||
|
||||
@@ -8,7 +8,7 @@ export default class VisiblePassword extends React.PureComponent {
|
||||
this.inputRef = React.createRef();
|
||||
|
||||
this.state = {
|
||||
value: this.props.value,
|
||||
value: this.props.value || '',
|
||||
visible: false
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ export default class VisiblePassword extends React.PureComponent {
|
||||
handleKeyDown(e) {
|
||||
if (e.keyCode == 27) {
|
||||
// Escape pressed
|
||||
this.setState({value: this.props.value, visible: false});
|
||||
this.setState({value: this.props.value || '', visible: false});
|
||||
if (this.props.onFinished) {
|
||||
this.props.onFinished();
|
||||
}
|
||||
@@ -68,7 +68,7 @@ export default class VisiblePassword extends React.PureComponent {
|
||||
return (
|
||||
<div tabIndex="-1" className="group-focus" onBlur={this.handleEditingFinished}>
|
||||
<input className="with-visibility"
|
||||
type={this.state.visible ? "text" : "password"}
|
||||
type={this.state.visible ? 'text' : 'password'}
|
||||
value={this.state.value}
|
||||
placeholder={this.props.placeholder}
|
||||
required={this.props.required ? 'required' : ''}
|
||||
|
||||
Reference in New Issue
Block a user