Import contact popup
This commit is contained in:
parent
733c0e4762
commit
ac1865f678
@ -24,18 +24,31 @@ export default class EditPeer {
|
||||
|
||||
private peerId: number;
|
||||
|
||||
private _disabled = false;
|
||||
private avatarSize = 120;
|
||||
|
||||
constructor(options: {
|
||||
peerId: number,
|
||||
peerId?: number,
|
||||
inputFields: EditPeer['inputFields'],
|
||||
listenerSetter: ListenerSetter,
|
||||
doNotEditAvatar?: boolean,
|
||||
withoutAvatar?: boolean,
|
||||
nextBtn?: HTMLButtonElement,
|
||||
avatarSize?: number
|
||||
}) {
|
||||
safeAssign(this, options);
|
||||
|
||||
if(!this.nextBtn) {
|
||||
this.nextBtn = ButtonCorner({icon: 'check'});
|
||||
} else if(!this.nextBtn.classList.contains('btn-corner')) {
|
||||
this.handleChange = () => {
|
||||
this.nextBtn.toggleAttribute('disabled', !this.isChanged() || this.disabled);
|
||||
};
|
||||
}
|
||||
|
||||
if(!options.withoutAvatar) {
|
||||
this.avatarElem = document.createElement('avatar-element') as AvatarElement;
|
||||
this.avatarElem.classList.add('avatar-placeholder', 'avatar-120');
|
||||
this.avatarElem.classList.add('avatar-placeholder', 'avatar-' + this.avatarSize);
|
||||
this.avatarElem.setAttribute('peer', '' + this.peerId);
|
||||
|
||||
if(!options.doNotEditAvatar) {
|
||||
@ -47,14 +60,58 @@ export default class EditPeer {
|
||||
|
||||
this.avatarEdit.container.append(this.avatarElem);
|
||||
}
|
||||
}
|
||||
|
||||
this.inputFields.forEach(inputField => {
|
||||
this.listenerSetter.add(inputField.input)('input', this.handleChange);
|
||||
});
|
||||
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
public get disabled() {
|
||||
return this._disabled;
|
||||
}
|
||||
|
||||
public set disabled(value) {
|
||||
this._disabled = value;
|
||||
this.inputFields.forEach(inputField => inputField.input.toggleAttribute('disabled', value));
|
||||
this.handleChange();
|
||||
}
|
||||
|
||||
public lockWithPromise(promise: Promise<any>, unlockOnSuccess = false) {
|
||||
this.disabled = true;
|
||||
promise.then(() => {
|
||||
if(unlockOnSuccess) {
|
||||
this.disabled = false;
|
||||
}
|
||||
}, () => {
|
||||
this.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
public isChanged = () => {
|
||||
return !!this.uploadAvatar || !!this.inputFields.find(inputField => inputField.isValid());
|
||||
if(this.uploadAvatar) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let validLength = 0, requiredLength = 0, requiredValidLength = 0;
|
||||
this.inputFields.forEach(inputField => {
|
||||
const isValid = inputField.isValid();
|
||||
if(isValid) {
|
||||
++validLength;
|
||||
|
||||
if(inputField.required) {
|
||||
++requiredValidLength;
|
||||
}
|
||||
}
|
||||
|
||||
if(inputField.required) {
|
||||
++requiredLength;
|
||||
}
|
||||
});
|
||||
|
||||
return requiredLength === requiredValidLength && validLength > 0;
|
||||
};
|
||||
|
||||
public handleChange = () => {
|
||||
|
@ -75,7 +75,9 @@ export type InputFieldOptions = {
|
||||
maxLength?: number,
|
||||
showLengthOn?: number,
|
||||
plainText?: true,
|
||||
animate?: true
|
||||
animate?: true,
|
||||
required?: boolean,
|
||||
validate?: () => boolean
|
||||
};
|
||||
|
||||
class InputField {
|
||||
@ -86,6 +88,9 @@ class InputField {
|
||||
|
||||
public originalValue: string;
|
||||
|
||||
public required: boolean;
|
||||
public validate: () => boolean;
|
||||
|
||||
//public onLengthChange: (length: number, isOverflow: boolean) => void;
|
||||
protected wasInputFakeClientHeight: number;
|
||||
// protected showScrollDebounced: () => void;
|
||||
@ -94,6 +99,13 @@ class InputField {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('input-field');
|
||||
|
||||
this.required = options.required;
|
||||
this.validate = options.validate;
|
||||
|
||||
if(this.required) {
|
||||
this.originalValue = '';
|
||||
}
|
||||
|
||||
if(options.maxLength) {
|
||||
options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3));
|
||||
}
|
||||
@ -259,8 +271,12 @@ class InputField {
|
||||
}
|
||||
}
|
||||
|
||||
public isChanged() {
|
||||
return this.value !== this.originalValue;
|
||||
}
|
||||
|
||||
public isValid() {
|
||||
return !this.input.classList.contains('error') && this.value !== this.originalValue;
|
||||
return !this.input.classList.contains('error') && this.isChanged() && (!this.validate || this.validate());
|
||||
}
|
||||
|
||||
public setOriginalValue(value: InputField['originalValue'] = '', silent = false) {
|
||||
|
88
src/components/popups/createContact.ts
Normal file
88
src/components/popups/createContact.ts
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import InputField from "../inputField";
|
||||
import PopupElement from ".";
|
||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||
import EditPeer from "../editPeer";
|
||||
import { _i18n } from "../../lib/langPack";
|
||||
import TelInputField from "../telInputField";
|
||||
import appUsersManager from "../../lib/appManagers/appUsersManager";
|
||||
import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
|
||||
import { toastNew } from "../toast";
|
||||
|
||||
export default class PopupCreateContact extends PopupElement {
|
||||
constructor() {
|
||||
super('popup-create-contact popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Add'});
|
||||
|
||||
_i18n(this.title, 'AddContactTitle');
|
||||
|
||||
attachClickEvent(this.btnConfirm, () => {
|
||||
const promise = appUsersManager.importContact(nameInputField.value, lastNameInputField.value, telInputField.value);
|
||||
|
||||
promise.then(() => {
|
||||
this.hide();
|
||||
}, (err) => {
|
||||
if(err.type === 'NO_USER') {
|
||||
toastNew({langPackKey: 'Contacts.PhoneNumber.NotRegistred'});
|
||||
editPeer.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
editPeer.lockWithPromise(promise);
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
const inputFields: InputField[] = [];
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('name-fields');
|
||||
const nameInputField = new InputField({
|
||||
label: 'FirstName',
|
||||
name: 'create-contact-name',
|
||||
maxLength: 70,
|
||||
required: true
|
||||
});
|
||||
const lastNameInputField = new InputField({
|
||||
label: 'LastName',
|
||||
name: 'create-contact-lastname',
|
||||
maxLength: 70
|
||||
});
|
||||
const telInputField = new TelInputField({required: true});
|
||||
inputFields.push(nameInputField, lastNameInputField, telInputField);
|
||||
|
||||
const onInput = () => {
|
||||
const name = nameInputField.value + ' ' + lastNameInputField.value;
|
||||
// const abbr = RichTextProcessor.getAbbreviation(name);
|
||||
editPeer.avatarElem.setAttribute('peer-title', name);
|
||||
editPeer.avatarElem.update();
|
||||
};
|
||||
|
||||
this.listenerSetter.add(nameInputField.input)('input', onInput);
|
||||
this.listenerSetter.add(lastNameInputField.input)('input', onInput);
|
||||
|
||||
const user = appUsersManager.getSelf();
|
||||
const formatted = formatPhoneNumber(user.phone);
|
||||
if(formatted) {
|
||||
telInputField.validate = () => {
|
||||
return !!telInputField.value.match(/\d/);
|
||||
};
|
||||
|
||||
telInputField.value = '+' + formatted.code.country_code;
|
||||
}
|
||||
|
||||
const editPeer = new EditPeer({
|
||||
inputFields,
|
||||
listenerSetter: this.listenerSetter,
|
||||
doNotEditAvatar: true,
|
||||
nextBtn: this.btnConfirm,
|
||||
avatarSize: 100
|
||||
});
|
||||
|
||||
div.append(nameInputField.container, lastNameInputField.container, editPeer.avatarElem);
|
||||
this.container.append(div, telInputField.container);
|
||||
|
||||
this.show();
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import appNavigationController, { NavigationItem } from "../appNavigationControl
|
||||
import { i18n, LangPackKey } from "../../lib/langPack";
|
||||
import findUpClassName from "../../helpers/dom/findUpClassName";
|
||||
import blurActiveElement from "../../helpers/dom/blurActiveElement";
|
||||
import ListenerSetter from "../../helpers/listenerSetter";
|
||||
|
||||
export type PopupButton = {
|
||||
text?: string,
|
||||
@ -34,7 +35,7 @@ export default class PopupElement {
|
||||
protected header = document.createElement('div');
|
||||
protected title = document.createElement('div');
|
||||
protected btnClose: HTMLElement;
|
||||
protected btnConfirm: HTMLElement;
|
||||
protected btnConfirm: HTMLButtonElement;
|
||||
protected body: HTMLElement;
|
||||
protected buttons: HTMLElement;
|
||||
|
||||
@ -44,6 +45,8 @@ export default class PopupElement {
|
||||
|
||||
protected navigationItem: NavigationItem;
|
||||
|
||||
protected listenerSetter: ListenerSetter;
|
||||
|
||||
constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) {
|
||||
this.element.classList.add('popup');
|
||||
this.element.className = 'popup' + (className ? ' ' + className : '');
|
||||
@ -54,6 +57,8 @@ export default class PopupElement {
|
||||
|
||||
this.header.append(this.title);
|
||||
|
||||
this.listenerSetter = new ListenerSetter();
|
||||
|
||||
if(options.closable) {
|
||||
this.btnClose = document.createElement('span');
|
||||
this.btnClose.classList.add('btn-icon', 'popup-close', 'tgico-close');
|
||||
@ -157,6 +162,7 @@ export default class PopupElement {
|
||||
this.onClose && this.onClose();
|
||||
this.element.classList.add('hiding');
|
||||
this.element.classList.remove('active');
|
||||
this.listenerSetter.removeAll();
|
||||
|
||||
if(this.btnClose) this.btnClose.removeEventListener('click', this.hide);
|
||||
rootScope.isOverlayActive = false;
|
||||
|
@ -1,14 +0,0 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import { SliderSuperTab } from "../../slider";
|
||||
|
||||
export default class AppAddContactTab extends SliderSuperTab {
|
||||
protected init() {
|
||||
this.container.classList.add('add-contact-container');
|
||||
this.setTitle('AddContactTitle');
|
||||
}
|
||||
}
|
@ -7,11 +7,13 @@
|
||||
import { SliderSuperTab } from "../../slider";
|
||||
import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
|
||||
import appUsersManager from "../../../lib/appManagers/appUsersManager";
|
||||
import appPhotosManager from "../../../lib/appManagers/appPhotosManager";
|
||||
import InputSearch from "../../inputSearch";
|
||||
import { isMobile } from "../../../helpers/userAgent";
|
||||
import { canFocus } from "../../../helpers/dom/canFocus";
|
||||
import windowSize from "../../../helpers/windowSize";
|
||||
import ButtonCorner from "../../buttonCorner";
|
||||
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
|
||||
import PopupCreateContact from "../../popups/createContact";
|
||||
|
||||
// TODO: поиск по людям глобальный, если не нашло в контактах никого
|
||||
|
||||
@ -29,8 +31,15 @@ export default class AppContactsTab extends SliderSuperTab {
|
||||
this.list.id = 'contacts';
|
||||
this.list.classList.add('contacts-container');
|
||||
|
||||
const btnAdd = ButtonCorner({icon: 'add', className: 'is-visible'});
|
||||
this.content.append(btnAdd);
|
||||
|
||||
attachClickEvent(btnAdd, () => {
|
||||
new PopupCreateContact();
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
appDialogsManager.setListClickListener(this.list, () => {
|
||||
(this.container.querySelector('.sidebar-close-button') as HTMLElement).click();
|
||||
this.close();
|
||||
}, undefined, true);
|
||||
|
||||
this.inputSearch = new InputSearch('Search', (value) => {
|
||||
|
@ -31,7 +31,7 @@ export default class AppEditContactTab extends SliderSuperTab {
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('edit-peer-container', 'edit-contact-container');
|
||||
this.setTitle('Edit');
|
||||
this.setTitle(this.peerId ? 'Edit' : 'AddContactTitle');
|
||||
|
||||
{
|
||||
const section = new SettingSection({noDelimiter: true});
|
||||
@ -51,13 +51,14 @@ export default class AppEditContactTab extends SliderSuperTab {
|
||||
maxLength: 70
|
||||
});
|
||||
|
||||
if(this.peerId) {
|
||||
const user = appUsersManager.getUser(this.peerId);
|
||||
|
||||
this.nameInputField.setOriginalValue(user.first_name);
|
||||
this.lastNameInputField.setOriginalValue(user.last_name);
|
||||
}
|
||||
|
||||
inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);
|
||||
|
||||
inputFields.push(this.nameInputField, this.lastNameInputField);
|
||||
|
||||
this.editPeer = new EditPeer({
|
||||
@ -68,6 +69,7 @@ export default class AppEditContactTab extends SliderSuperTab {
|
||||
});
|
||||
this.content.append(this.editPeer.nextBtn);
|
||||
|
||||
if(this.peerId) {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('avatar-edit');
|
||||
div.append(this.editPeer.avatarElem);
|
||||
@ -114,6 +116,9 @@ export default class AppEditContactTab extends SliderSuperTab {
|
||||
profileSubtitleDiv.append(i18n('EditContact.OriginalName'));
|
||||
|
||||
section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper, notificationsRow.container);
|
||||
} else {
|
||||
section.content.append(inputWrapper);
|
||||
}
|
||||
|
||||
this.scrollable.append(section.container);
|
||||
|
||||
@ -128,7 +133,7 @@ export default class AppEditContactTab extends SliderSuperTab {
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
}
|
||||
|
||||
{
|
||||
if(this.peerId) {
|
||||
const section = new SettingSection({
|
||||
|
||||
});
|
||||
|
110
src/components/telInputField.ts
Normal file
110
src/components/telInputField.ts
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import placeCaretAtEnd from "../helpers/dom/placeCaretAtEnd";
|
||||
import { formatPhoneNumber } from "../helpers/formatPhoneNumber";
|
||||
import { isApple, isAndroid, isAppleMobile } from "../helpers/userAgent";
|
||||
import { HelpCountry, HelpCountryCode } from "../layer";
|
||||
import InputField, { InputFieldOptions } from "./inputField";
|
||||
|
||||
export default class TelInputField extends InputField {
|
||||
private pasted = false;
|
||||
public lastValue = '';
|
||||
|
||||
constructor(options: InputFieldOptions & {
|
||||
onInput?: (formatted: ReturnType<typeof formatPhoneNumber>) => void
|
||||
} = {}) {
|
||||
super({
|
||||
label: 'Contacts.PhoneNumber.Placeholder',
|
||||
//plainText: true,
|
||||
name: 'phone',
|
||||
...options
|
||||
});
|
||||
|
||||
this.container.classList.add('input-field-phone');
|
||||
|
||||
let telEl = this.input;
|
||||
if(telEl instanceof HTMLInputElement) {
|
||||
telEl.type = 'tel';
|
||||
telEl.autocomplete = 'rr55RandomRR55';
|
||||
} else {
|
||||
telEl.inputMode = 'decimal';
|
||||
|
||||
const pixelRatio = window.devicePixelRatio;
|
||||
if(pixelRatio > 1) {
|
||||
let letterSpacing: number;
|
||||
if(isApple) {
|
||||
letterSpacing = pixelRatio * -.16;
|
||||
} else if(isAndroid) {
|
||||
letterSpacing = 0;
|
||||
}
|
||||
|
||||
telEl.style.setProperty('--letter-spacing', letterSpacing + 'px');
|
||||
}
|
||||
|
||||
const originalFunc = this.setValueSilently.bind(this);
|
||||
this.setValueSilently = (value) => {
|
||||
originalFunc(value);
|
||||
placeCaretAtEnd(this.input, true);
|
||||
};
|
||||
}
|
||||
|
||||
telEl.addEventListener('input', () => {
|
||||
//console.log('input', this.value);
|
||||
telEl.classList.remove('error');
|
||||
|
||||
const value = this.value;
|
||||
const diff = Math.abs(value.length - this.lastValue.length);
|
||||
if(diff > 1 && !this.pasted && isAppleMobile) {
|
||||
this.setValueSilently(this.lastValue + value);
|
||||
}
|
||||
|
||||
this.pasted = false;
|
||||
|
||||
this.setLabel();
|
||||
|
||||
let formattedPhoneNumber: ReturnType<typeof formatPhoneNumber>;
|
||||
let formatted: string, country: HelpCountry, countryCode: HelpCountryCode, leftPattern = '';
|
||||
if(this.value.replace(/\++/, '+') === '+') {
|
||||
this.setValueSilently('+');
|
||||
} else {
|
||||
formattedPhoneNumber = formatPhoneNumber(this.value);
|
||||
formatted = formattedPhoneNumber.formatted;
|
||||
country = formattedPhoneNumber.country;
|
||||
leftPattern = formattedPhoneNumber.leftPattern;
|
||||
countryCode = formattedPhoneNumber.code;
|
||||
this.setValueSilently(this.lastValue = formatted ? '+' + formatted : '');
|
||||
}
|
||||
|
||||
telEl.dataset.leftPattern = leftPattern/* .replace(/X/g, '0') */;
|
||||
|
||||
//console.log(formatted, country);
|
||||
|
||||
options.onInput && options.onInput(formattedPhoneNumber);
|
||||
});
|
||||
|
||||
telEl.addEventListener('paste', () => {
|
||||
this.pasted = true;
|
||||
//console.log('paste', telEl.value);
|
||||
});
|
||||
|
||||
/* telEl.addEventListener('change', (e) => {
|
||||
console.log('change', telEl.value);
|
||||
}); */
|
||||
|
||||
telEl.addEventListener('keypress', (e) => {
|
||||
//console.log('keypress', this.value);
|
||||
if(/\D/.test(e.key) && !(e.metaKey || e.ctrlKey) && e.key !== 'Backspace' && !(e.key === '+' && e.shiftKey/* && !this.value */)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
/* telEl.addEventListener('focus', function(this: typeof telEl, e) {
|
||||
this.removeAttribute('readonly'); // fix autocomplete
|
||||
});*/
|
||||
}
|
||||
}
|
@ -570,6 +570,7 @@ const lang = {
|
||||
"Alert.UserDoesntExists": "Sorry, this user doesn't seem to exist.",
|
||||
"Appearance.Reset": "Reset to Defaults",
|
||||
"Bio.Description": "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco",
|
||||
"Contacts.PhoneNumber.NotRegistred": "The person with this phone number is not registered on Telegram yet.",
|
||||
"Channel.UsernameAboutChannel": "People can share this link with others and can find your channel using Telegram search.",
|
||||
"Channel.UsernameAboutGroup": "People can share this link with others and find your group using Telegram search.",
|
||||
"Chat.CopySelectedText": "Copy Selected Text",
|
||||
|
@ -23,6 +23,7 @@ const lang = {
|
||||
"StartMessaging": "Start Messaging",
|
||||
|
||||
// * macos
|
||||
"Contacts.PhoneNumber.Placeholder": "Phone Number",
|
||||
"Login.Next": "Next",
|
||||
"Login.ContinueOnLanguage": "Continue in English",
|
||||
"Login.QR.Title": "Log in to Telegram by QR Code",
|
||||
|
@ -17,7 +17,7 @@ import cleanUsername from "../../helpers/cleanUsername";
|
||||
import { tsNow } from "../../helpers/date";
|
||||
import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
|
||||
import { safeReplaceObject, isObject } from "../../helpers/object";
|
||||
import { Chat, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
|
||||
import { Chat, InputContact, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
|
||||
import I18n, { i18n, LangPackKey } from "../langPack";
|
||||
//import apiManager from '../mtproto/apiManager';
|
||||
import apiManager from '../mtproto/mtprotoworker';
|
||||
@ -680,75 +680,50 @@ export class AppUsersManager {
|
||||
}
|
||||
}
|
||||
|
||||
/* function importContact (phone, firstName, lastName) {
|
||||
return MtpApiManager.invokeApi('contacts.importContacts', {
|
||||
contacts: [{
|
||||
_: 'inputPhoneContact',
|
||||
client_id: '1',
|
||||
phone: phone,
|
||||
first_name: firstName,
|
||||
last_name: lastName
|
||||
}],
|
||||
replace: false
|
||||
}).then(function (importedContactsResult) {
|
||||
saveApiUsers(importedContactsResult.users)
|
||||
|
||||
var foundUserID = false
|
||||
angular.forEach(importedContactsResult.imported, function (importedContact) {
|
||||
onContactUpdated(foundUserID = importedContact.user_id, true)
|
||||
})
|
||||
|
||||
return foundUserID || false
|
||||
})
|
||||
public importContact(first_name: string, last_name: string, phone: string) {
|
||||
return this.importContacts([{
|
||||
first_name,
|
||||
last_name,
|
||||
phones: [phone]
|
||||
}]).then(userIds => {
|
||||
if(!userIds.length) {
|
||||
const error = new Error();
|
||||
(error as any).type = 'NO_USER';
|
||||
throw error;
|
||||
}
|
||||
|
||||
function importContacts (contacts) {
|
||||
var inputContacts = [],
|
||||
i
|
||||
var j
|
||||
return userIds[0];
|
||||
});
|
||||
}
|
||||
|
||||
for (i = 0; i < contacts.length; i++) {
|
||||
for (j = 0; j < contacts[i].phones.length; j++) {
|
||||
public importContacts(contacts: {phones: string[], first_name: string, last_name: string}[]) {
|
||||
const inputContacts: InputContact[] = [];
|
||||
|
||||
for(let i = 0; i < contacts.length; ++i) {
|
||||
for(let j = 0; j < contacts[i].phones.length; ++j) {
|
||||
inputContacts.push({
|
||||
_: 'inputPhoneContact',
|
||||
client_id: (i << 16 | j).toString(10),
|
||||
phone: contacts[i].phones[j],
|
||||
first_name: contacts[i].first_name,
|
||||
last_name: contacts[i].last_name
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return MtpApiManager.invokeApi('contacts.importContacts', {
|
||||
contacts: inputContacts,
|
||||
replace: false
|
||||
}).then(function (importedContactsResult) {
|
||||
saveApiUsers(importedContactsResult.users)
|
||||
return apiManager.invokeApi('contacts.importContacts', {
|
||||
contacts: inputContacts
|
||||
}).then((importedContactsResult) => {
|
||||
this.saveApiUsers(importedContactsResult.users);
|
||||
|
||||
var result = []
|
||||
angular.forEach(importedContactsResult.imported, function (importedContact) {
|
||||
onContactUpdated(importedContact.user_id, true)
|
||||
result.push(importedContact.user_id)
|
||||
})
|
||||
|
||||
return result
|
||||
})
|
||||
} */
|
||||
|
||||
/* public deleteContacts(userIds: number[]) {
|
||||
var ids: any[] = [];
|
||||
userIds.forEach((userId) => {
|
||||
ids.push(this.getUserInput(userId));
|
||||
})
|
||||
|
||||
return apiManager.invokeApi('contacts.deleteContacts', {
|
||||
id: ids
|
||||
}).then(() => {
|
||||
userIds.forEach((userId) => {
|
||||
this.onContactUpdated(userId, false);
|
||||
const userIds = importedContactsResult.imported.map((importedContact) => {
|
||||
this.onContactUpdated(importedContact.user_id, true);
|
||||
return importedContact.user_id;
|
||||
});
|
||||
|
||||
return userIds;
|
||||
});
|
||||
} */
|
||||
}
|
||||
|
||||
public getTopPeers(type: TopPeerType) {
|
||||
if(this.getTopPeersPromises[type]) return this.getTopPeersPromises[type];
|
||||
@ -889,6 +864,14 @@ export class AppUsersManager {
|
||||
}
|
||||
|
||||
public addContact(userId: number, first_name: string, last_name: string, phone: string, showPhone?: true) {
|
||||
/* if(!userId) {
|
||||
return this.importContacts([{
|
||||
first_name,
|
||||
last_name,
|
||||
phones: [phone]
|
||||
}]);
|
||||
} */
|
||||
|
||||
return apiManager.invokeApi('contacts.addContact', {
|
||||
id: this.getUserInput(userId),
|
||||
first_name,
|
||||
|
@ -40,6 +40,7 @@ import { getCountryEmoji } from "../vendor/emoji";
|
||||
import simulateEvent from "../helpers/dom/dispatchEvent";
|
||||
import stateStorage from "../lib/stateStorage";
|
||||
import rootScope from "../lib/rootScope";
|
||||
import TelInputField from "../components/telInputField";
|
||||
|
||||
//import _countries from '../countries_pretty.json';
|
||||
let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement;
|
||||
@ -163,7 +164,7 @@ let onFirstMount = () => {
|
||||
lastCountrySelected = countries.find(c => c.default_name === defaultName);
|
||||
lastCountryCodeSelected = lastCountrySelected.country_codes.find(_countryCode => _countryCode.country_code === countryCode);
|
||||
|
||||
telInputField.value = lastValue = phoneCode;
|
||||
telInputField.value = telInputField.lastValue = phoneCode;
|
||||
hidePicker();
|
||||
setTimeout(() => {
|
||||
telEl.focus();
|
||||
@ -269,88 +270,24 @@ let onFirstMount = () => {
|
||||
else countryInput.focus();
|
||||
});
|
||||
|
||||
let pasted = false;
|
||||
let lastValue = '';
|
||||
|
||||
const telInputField = new InputField({
|
||||
label: 'Login.PhoneLabel',
|
||||
//plainText: true,
|
||||
name: 'phone'
|
||||
});
|
||||
|
||||
telInputField.container.classList.add('input-field-phone');
|
||||
|
||||
let telEl = telInputField.input;
|
||||
if(telEl instanceof HTMLInputElement) {
|
||||
telEl.type = 'tel';
|
||||
telEl.autocomplete = 'rr55RandomRR55';
|
||||
} else {
|
||||
telEl.inputMode = 'decimal';
|
||||
|
||||
const pixelRatio = window.devicePixelRatio;
|
||||
if(pixelRatio > 1) {
|
||||
let letterSpacing: number;
|
||||
if(isApple) {
|
||||
letterSpacing = pixelRatio * -.16;
|
||||
} else if(isAndroid) {
|
||||
letterSpacing = 0;
|
||||
}
|
||||
|
||||
telEl.style.setProperty('--letter-spacing', letterSpacing + 'px');
|
||||
}
|
||||
|
||||
const originalFunc = telInputField.setValueSilently.bind(telInputField);
|
||||
telInputField.setValueSilently = (value) => {
|
||||
originalFunc(value);
|
||||
placeCaretAtEnd(telInputField.input, true);
|
||||
};
|
||||
}
|
||||
|
||||
telEl.addEventListener('input', () => {
|
||||
//console.log('input', this.value);
|
||||
telEl.classList.remove('error');
|
||||
|
||||
const telInputField = new TelInputField({
|
||||
onInput: (formatted) => {
|
||||
lottieLoader.loadLottieWorkers();
|
||||
|
||||
const value = telInputField.value;
|
||||
const diff = Math.abs(value.length - lastValue.length);
|
||||
if(diff > 1 && !pasted && isAppleMobile) {
|
||||
telInputField.setValueSilently(lastValue + value);
|
||||
}
|
||||
|
||||
pasted = false;
|
||||
|
||||
telInputField.setLabel();
|
||||
|
||||
let formatted: string, country: HelpCountry, countryCode: HelpCountryCode, leftPattern = '';
|
||||
if(telInputField.value.replace(/\++/, '+') === '+') {
|
||||
telInputField.setValueSilently('+');
|
||||
} else {
|
||||
const o = formatPhoneNumber(telInputField.value);
|
||||
formatted = o.formatted;
|
||||
country = o.country;
|
||||
leftPattern = o.leftPattern;
|
||||
countryCode = o.code;
|
||||
telInputField.setValueSilently(lastValue = formatted ? '+' + formatted : '');
|
||||
}
|
||||
|
||||
telEl.dataset.leftPattern = leftPattern/* .replace(/X/g, '0') */;
|
||||
|
||||
//console.log(formatted, country);
|
||||
|
||||
const {country, code} = formatted;
|
||||
let countryName = country ? country.name || country.default_name : ''/* 'Unknown' */;
|
||||
if(countryName !== countryInputField.value && (
|
||||
!lastCountrySelected ||
|
||||
!country ||
|
||||
!countryCode || (
|
||||
!code || (
|
||||
lastCountrySelected !== country &&
|
||||
lastCountryCodeSelected.country_code !== countryCode.country_code
|
||||
lastCountryCodeSelected.country_code !== code.country_code
|
||||
)
|
||||
)
|
||||
) {
|
||||
replaceContent(countryInput, country ? i18n(country.default_name as any) : countryName);
|
||||
lastCountrySelected = country;
|
||||
lastCountryCodeSelected = countryCode;
|
||||
lastCountryCodeSelected = code;
|
||||
}
|
||||
|
||||
//if(country && (telInputField.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) {
|
||||
@ -359,24 +296,15 @@ let onFirstMount = () => {
|
||||
} else {
|
||||
btnNext.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
telEl.addEventListener('paste', () => {
|
||||
pasted = true;
|
||||
//console.log('paste', telEl.value);
|
||||
});
|
||||
|
||||
/* telEl.addEventListener('change', (e) => {
|
||||
console.log('change', telEl.value);
|
||||
}); */
|
||||
const telEl = telInputField.input;
|
||||
|
||||
telEl.addEventListener('keypress', (e) => {
|
||||
//console.log('keypress', this.value);
|
||||
if(!btnNext.style.visibility &&/* this.value.length >= 9 && */ e.key === 'Enter') {
|
||||
return onSubmit();
|
||||
} else if(/\D/.test(e.key) && !(e.metaKey || e.ctrlKey) && e.key !== 'Backspace' && !(e.key === '+' && e.shiftKey/* && !this.value */)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -147,7 +147,7 @@
|
||||
font-size: 1rem;
|
||||
border-radius: $border-radius-medium;
|
||||
|
||||
&:not(:focus):empty ~ label {
|
||||
&[data-placeholder]:not(:focus):empty ~ label {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@ -189,3 +189,24 @@
|
||||
margin-top: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-create-contact {
|
||||
.name-fields {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
padding-left: 116px;
|
||||
margin-top: 1rem;
|
||||
|
||||
.input-field:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user