support fro unique aliases, https://github.com/tinode/chat/issues/446
This commit is contained in:
@@ -24,7 +24,8 @@ export default class AccountSettingsView extends React.Component {
|
||||
description: _clip(me.public ? me.public.note : undefined, MAX_TOPIC_DESCRIPTION_LENGTH),
|
||||
avatar: makeImageUrl(me.public ? me.public.photo : null),
|
||||
credentials: me.getCredentials() || [],
|
||||
credEdit: undefined
|
||||
credEdit: undefined,
|
||||
alias: ((me.tags() || []).find(tag => tag.startsWith('alias:')) || '').substring(6),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -123,6 +124,12 @@ export default class AccountSettingsView extends React.Component {
|
||||
description="Label for user address (ID)" /></label>
|
||||
<tt>{this.props.myUserId}</tt>
|
||||
</div>
|
||||
{this.state.alias ?
|
||||
<div className="group">
|
||||
<label className="small"><FormattedMessage id="label_alias" defaultMessage="Alias:"
|
||||
description="Label for user or topic alias" /></label>
|
||||
<tt>@{this.state.alias}</tt>
|
||||
</div> : null}
|
||||
<div className="group">
|
||||
<BadgeList trustedBadges={this.props.trustedBadges} />
|
||||
</div>
|
||||
|
||||
+39
-8
@@ -16,7 +16,8 @@ import ShowQRCode from '../widgets/show-qrcode.jsx';
|
||||
import TopicCommonView from './topic-common-view.jsx';
|
||||
import TopicSecurity from '../widgets/topic-security.jsx';
|
||||
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH, NO_ACCESS_MODE } from '../config.js';
|
||||
import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH,
|
||||
NO_ACCESS_MODE, TOAST_DURATION } from '../config.js';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { theCard, clipStr } from '../lib/utils.js';
|
||||
@@ -82,6 +83,11 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Scan QR Code',
|
||||
description: 'Title for scanning QR code'
|
||||
},
|
||||
text_copied: {
|
||||
id: 'text_copied',
|
||||
defaultMessage: 'Copied to clipboard',
|
||||
description: 'Notification that text has been copied to clipboard'
|
||||
}
|
||||
});
|
||||
|
||||
class InfoView extends React.Component {
|
||||
@@ -127,8 +133,8 @@ class InfoView extends React.Component {
|
||||
this.handleUnarchive = this.handleUnarchive.bind(this);
|
||||
this.handlePermissionsChanged = this.handlePermissionsChanged.bind(this);
|
||||
this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this);
|
||||
this.handleCopyID = this.handleCopyID.bind(this);
|
||||
this.handleShowQRCode = this.handleShowQRCode.bind(this);
|
||||
this.handleCopyToClipboard = this.handleCopyToClipboard.bind(this);
|
||||
this.handleShowAddMembers = this.handleShowAddMembers.bind(this);
|
||||
this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this);
|
||||
this.handleMemberSelected = this.handleMemberSelected.bind(this);
|
||||
@@ -384,16 +390,20 @@ class InfoView extends React.Component {
|
||||
this.props.onNavigate(`perm/${which}`);
|
||||
}
|
||||
|
||||
handleCopyID(e) {
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText(this.props.myUserId);
|
||||
}
|
||||
|
||||
handleShowQRCode(e) {
|
||||
e.preventDefault();
|
||||
this.props.onNavigate('qrcode');
|
||||
}
|
||||
|
||||
handleCopyToClipboard(e, text) {
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText(text).then(_ => {
|
||||
this.setState({toast: this.props.intl.formatMessage(messages.text_copied)});
|
||||
setTimeout(_ => { this.setState({toast: ''}); }, TOAST_DURATION);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
handleShowAddMembers(e) {
|
||||
e.preventDefault();
|
||||
this.props.onInitFind();
|
||||
@@ -463,8 +473,12 @@ class InfoView extends React.Component {
|
||||
const panelTitle = formatMessage((view == 'perm' ? messages['perm_' + args[0]] : messages[view])
|
||||
|| messages['info']);
|
||||
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
const alias = topic && topic.alias();
|
||||
|
||||
return (
|
||||
<div id="info-view">
|
||||
<div className={`toast${this.state.toast ? ' show' : ''}`}>{this.state.toast}</div>
|
||||
<div className="caption-panel" id="info-caption-panel">
|
||||
<div className="panel-title" id="info-title">{panelTitle}</div>
|
||||
<div>
|
||||
@@ -581,6 +595,7 @@ class InfoView extends React.Component {
|
||||
: null
|
||||
}
|
||||
{!this.state.isSelf ?
|
||||
<>
|
||||
<div className="panel-form-row">
|
||||
<div>
|
||||
<label className="small"><FormattedMessage id="label_user_id" defaultMessage="ID:"
|
||||
@@ -588,7 +603,7 @@ class InfoView extends React.Component {
|
||||
<tt>{this.state.address}</tt>
|
||||
</div>
|
||||
<div style={{marginLeft: 'auto'}}>
|
||||
<a href="#" onClick={this.handleCopyID}>
|
||||
<a href="#" onClick={e => {this.handleCopyToClipboard(e, this.state.address);}}>
|
||||
<i className="material-icons">content_copy</i>
|
||||
</a>
|
||||
<a href="#" onClick={this.handleShowQRCode}>
|
||||
@@ -596,6 +611,22 @@ class InfoView extends React.Component {
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{alias ?
|
||||
<div className="panel-form-row">
|
||||
<div>
|
||||
<label className="small"><FormattedMessage id="label_alias" defaultMessage="Alias:"
|
||||
description="Label for user or topic alias" /></label>
|
||||
<tt>{alias}</tt>
|
||||
</div>
|
||||
<div style={{marginLeft: 'auto'}}>
|
||||
<a href="#" onClick={e => {this.handleCopyToClipboard(e, alias);}}>
|
||||
<i className="material-icons">content_copy</i>
|
||||
</a>
|
||||
<i className="material-icons" style={{opacity: 0}}>qr_code</i>
|
||||
</div>
|
||||
</div>
|
||||
: null}
|
||||
</>
|
||||
: null
|
||||
}
|
||||
{this.state.trustedBadges.length > 0 ?
|
||||
|
||||
@@ -10,7 +10,7 @@ import NewTopicGroup from '../widgets/new-topic-group.jsx';
|
||||
import SearchContacts from '../widgets/search-contacts.jsx';
|
||||
|
||||
import HashNavigation from '../lib/navigation.js';
|
||||
import { theCard } from '../lib/utils.js';
|
||||
import { asEmail, asPhone, theCard } from '../lib/utils.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
search_for_contacts: {
|
||||
@@ -57,6 +57,24 @@ class NewTopicView extends React.Component {
|
||||
}
|
||||
|
||||
handleSearchContacts(query) {
|
||||
query = query.trim();
|
||||
if (!query) {
|
||||
query = Tinode.DEL_CHAR;
|
||||
} else if (!/[\s,:]/.test(query)) {
|
||||
// No colons, spaces or commas. Try as email or phone.
|
||||
// If not email or phone, treat as alias.
|
||||
const email = asEmail(query);
|
||||
if (email) {
|
||||
query = `email:${email}`;
|
||||
} else {
|
||||
const tel = asPhone(query);
|
||||
if (tel) {
|
||||
query = `tel:${tel}`;
|
||||
} else {
|
||||
query = `alias:${query}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.props.onSearchContacts(query);
|
||||
this.setState({searchQuery: Tinode.isNullValue(query) ? null : query});
|
||||
}
|
||||
@@ -125,7 +143,7 @@ class NewTopicView extends React.Component {
|
||||
contacts={this.props.searchResults}
|
||||
myUserId={this.props.myUserId}
|
||||
emptyListMessage={no_contacts_placeholder}
|
||||
showSelfTopic={true}
|
||||
showSelfTopic={!this.state.searchQuery}
|
||||
showOnline={false}
|
||||
showUnread={false}
|
||||
showContextMenu={false}
|
||||
|
||||
@@ -89,6 +89,11 @@ const messages = defineMessages({
|
||||
id: 'password_reset_success',
|
||||
defaultMessage: 'Password reset successfully',
|
||||
description: 'Notification message that the password was successfully reset.'
|
||||
},
|
||||
select_country: {
|
||||
id: 'select_country',
|
||||
defaultMessage: 'Select country',
|
||||
description: 'Placeholder for the country selector'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1763,7 +1768,7 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
|
||||
handleShowCountrySelector(code, dial, selectedCallback) {
|
||||
this.handleShowAlert("Select country",
|
||||
this.handleShowAlert(this.props.intl.formatMessage(messages.select_country),
|
||||
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<PhoneCountrySelector
|
||||
@@ -1773,7 +1778,7 @@ class TinodeWeb extends React.Component {
|
||||
selectedCallback(c, d);
|
||||
}} />
|
||||
</Suspense>,
|
||||
null, null, _ => {}, "Cancel");
|
||||
null, null, _ => {}, null);
|
||||
}
|
||||
|
||||
handleStartVideoCall() {
|
||||
|
||||
Reference in New Issue
Block a user