deleting contacts

This commit is contained in:
or-else
2019-06-07 16:26:42 -07:00
parent 6cb2b77f69
commit 53d748a7bd
16 changed files with 411 additions and 136 deletions
+121 -45
View File
@@ -10,31 +10,38 @@ import PermissionsEditor from '../widgets/permissions-editor.jsx';
import TagManager from '../widgets/tag-manager.jsx';
import { makeImageUrl } from '../lib/blob-helpers.js';
import { arrayEqual, vcard } from '../lib/utils.js';
import { arrayEqual, asEmail, asPhone, vcard } from '../lib/utils.js';
export default class EditAccountView extends React.Component {
constructor(props) {
super(props);
const me = this.props.tinode.getMeTopic();
const defacs = me ? me.getDefaultAccess() : null;
const fnd = this.props.tinode.getFndTopic();
const defacs = me.getDefaultAccess();
this.state = {
fullName: me.public ? me.public.fn : undefined,
avatar: makeImageUrl(me.public ? me.public.photo : null),
auth: defacs ? defacs.auth : null,
anon: defacs ? defacs.anon : null,
fndSubscribed: false,
tags: fnd.tags(),
tags: me.tags(),
credentials: me.getCredentials() || [],
addCredActive: false,
addCredInvalid: false,
newCred: '',
showPermissionEditorFor: undefined,
previousOnTags: fnd.onTagsUpdated
previousOnTags: me.onTagsUpdated
};
this.tnNewTags = this.tnNewTags.bind(this);
this.tnCredsUpdated = this.tnCredsUpdated.bind(this);
this.handleFullNameUpdate = this.handleFullNameUpdate.bind(this);
this.handlePasswordUpdate = this.handlePasswordUpdate.bind(this);
this.handleImageChanged = this.handleImageChanged.bind(this);
this.handleCheckboxClick = this.handleCheckboxClick.bind(this);
this.handleStartAddCred = this.handleStartAddCred.bind(this);
this.handleCredChange = this.handleCredChange.bind(this);
this.handleCredKeyDown = this.handleCredKeyDown.bind(this);
this.handleCredEntered = this.handleCredEntered.bind(this);
this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this);
this.handleHidePermissionsEditor = this.handleHidePermissionsEditor.bind(this);
this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this);
@@ -42,31 +49,26 @@ export default class EditAccountView extends React.Component {
}
componentDidMount() {
const fnd = this.props.tinode.getFndTopic();
fnd.onTagsUpdated = this.tnNewTags;
if (!fnd.isSubscribed()) {
fnd.subscribe(fnd.startMetaQuery().withTags().build())
.then((ctrl) => {
this.setState({fndSubscribed: true});
})
.catch((err) => {
this.props.onError(err.message, 'err');
});
}
const me = this.props.tinode.getMeTopic();
me.onCredsUpdated = this.tnCredsUpdated;
me.onTagsUpdated = this.tnNewTags;
}
componentWillUnmount() {
const fnd = this.props.tinode.getFndTopic();
fnd.onTagsUpdated = this.state.previousOnTags;
if (fnd.isSubscribed() && this.state.fndSubscribed) {
fnd.leave();
}
const me = this.props.tinode.getMeTopic();
me.onTagsUpdated = this.state.previousOnTags;
me.onCredsUpdated = undefined;
}
tnNewTags(tags) {
this.setState({tags: tags});
}
tnCredsUpdated(creds) {
console.log("tnCredsUpdated", creds, new Error());
this.setState({credentials: creds || []});
}
handleFullNameUpdate(fn) {
this.setState({fullName: fn});
this.props.onUpdateAccount(undefined, vcard(fn, null));
@@ -90,6 +92,49 @@ export default class EditAccountView extends React.Component {
}
}
handleStartAddCred() {
this.setState({addCredActive: true});
}
handleCredChange(e) {
this.setState({newCred: e.target.value, addCredInvalid: false});
}
handleCredKeyDown(e) {
if (e.keyCode === 27) {
// Escape pressed
this.setState({newCred: '', addCredActive: false});
} else if (e.keyCode === 13) {
// Enter pressed
this.handleCredEntered(e);
}
}
handleCredEntered(e) {
let value = this.state.newCred.trim();
if (!value) {
this.setState({addCredActive: false, addCredInvalid: false});
return;
}
let val = asPhone(value);
let method;
if (val) {
method = 'tel';
} else {
val = asEmail(value);
if (val) {
method = 'email';
}
}
if (method) {
this.props.onCredAdd(method, val);
this.setState({addCredActive: false, newCred: ''});
} else {
this.setState({addCredInvalid: true});
}
}
handleLaunchPermissionsEditor(which) {
this.setState({
showPermissionEditorFor: which,
@@ -120,13 +165,25 @@ export default class EditAccountView extends React.Component {
}
render() {
var tags = [];
this.state.tags.map(function(tag) {
/*
let tags = [];
this.state.tags.map((tag) => {
tags.push(<span className="badge" key={tags.length}>{tag}</span>);
});
if (tags.length == 0) {
tags = <i><FormattedMessage id="tags_not_found" /></i>;
}
*/
let credentials = [];
this.state.credentials.map((cred) => {
credentials.push(<div key={cred.meth + ":" + cred.val}>{cred.meth}: <tt>{cred.val}</tt>
{!cred.done ?
<a href="javascript:;"
onClick={this.props.onCredConfirm.bind(this, cred.meth, cred.val)}>confirm</a>
: null} <a href="javascript:;" onClick={this.props.onCredDelete.bind(this, cred.meth, cred.val)}><i
className="material-icons gray">delete_outline</i></a></div>);
});
return (
<React.Fragment>{this.state.showPermissionEditorFor ?
<PermissionsEditor
@@ -170,26 +227,6 @@ export default class EditAccountView extends React.Component {
onError={this.props.onError} />
</div>
<div className="hr" />
<div className="panel-form-column">
<div className="panel-form-row">
<label><FormattedMessage id="label_user_id" defaultMessage="Address:"
description="Label for user address (ID)" /></label>
<tt>{this.props.myUserId}</tt>
</div>
<div>
<label className="small">
<FormattedMessage id="label_default_access_mode" defaultMessage="Default access mode:"
description="Label for default access mode" />
</label>
</div>
<div className="quoted">
<div>Auth: <tt className="clickable"
onClick={this.handleLaunchPermissionsEditor.bind(this, 'auth')}>{this.state.auth}</tt></div>
<div>Anon: <tt className="clickable"
onClick={this.handleLaunchPermissionsEditor.bind(this, 'anon')}>{this.state.anon}</tt></div>
</div>
</div>
<div className="hr" />
<div className="panel-form-row">
<label htmlFor="message-sound">
<FormattedMessage id="label_message_sound" defaultMessage="Message sound:"
@@ -207,7 +244,7 @@ export default class EditAccountView extends React.Component {
:
<FormattedMessage id="label_push_notifications_disabled"
defaultMessage="Notification alerts (requires HTTPS):"
description="Label for push notifications switch (disabled)" />
description="Label for push notifications switch" />
}
</label>
<CheckBox name="alert" id="desktop-alerts"
@@ -224,6 +261,45 @@ export default class EditAccountView extends React.Component {
onSubmit={this.handleTagsUpdated} />
}</FormattedMessage>
<div className="hr" />
<div className="panel-form-column">
<div>
<label className="small">
<FormattedMessage id="label_user_contacts" defaultMessage="Contacts:"
description="Label for user contacts" />
</label>
</div>
<div className="quoted">
{credentials}
{this.state.addCredActive ?
<input type="text" value={this.state.value}
className={this.state.addCredInvalid ? "invalid" : null}
placeholder="Phone number or email" required="required" autoFocus
onChange={this.handleCredChange} onKeyDown={this.handleCredKeyDown} onBlur={this.handleCredEntered} />
: null}
<div><a href="javascript:;" onClick={this.handleStartAddCred}>+ Add another</a></div>
</div>
</div>
<div className="hr" />
<div className="panel-form-column">
<div className="panel-form-row">
<label className="small"><FormattedMessage id="label_user_id" defaultMessage="Address:"
description="Label for user address (ID)" /></label>
<tt>{this.props.myUserId}</tt>
</div>
<div>
<label className="small">
<FormattedMessage id="label_default_access_mode" defaultMessage="Default access mode:"
description="Label for default access mode" />
</label>
</div>
<div className="quoted">
<div>Auth: <tt className="clickable"
onClick={this.handleLaunchPermissionsEditor.bind(this, 'auth')}>{this.state.auth}</tt></div>
<div>Anon: <tt className="clickable"
onClick={this.handleLaunchPermissionsEditor.bind(this, 'anon')}>{this.state.anon}</tt></div>
</div>
</div>
<div className="hr" />
<div className="panel-form-column">
<a href="javascript:;" className="red flat-button" onClick={this.props.onLogout}>
<i className="material-icons">exit_to_app</i> <FormattedMessage id="button_logout"