From baa681634b7e284090d24181ab556b39dc540ba4 Mon Sep 17 00:00:00 2001 From: fe-dev Date: Tue, 24 May 2022 10:13:11 +0300 Subject: [PATCH] UI: Phone input with country flag select --- ui-ngx/package.json | 1 + .../components/phone-input.component.html | 51 + .../components/phone-input.component.scss | 60 + .../components/phone-input.component.ts | 215 +++ .../src/app/shared/models/country.models.ts | 1587 +++++++++++++++++ ui-ngx/src/app/shared/shared.module.ts | 7 +- .../assets/locale/locale.constant-en_US.json | 6 + ui-ngx/yarn.lock | 5 + 8 files changed, 1930 insertions(+), 2 deletions(-) create mode 100644 ui-ngx/src/app/shared/components/phone-input.component.html create mode 100644 ui-ngx/src/app/shared/components/phone-input.component.scss create mode 100644 ui-ngx/src/app/shared/components/phone-input.component.ts create mode 100644 ui-ngx/src/app/shared/models/country.models.ts diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 4f4316fced..feef69a2c9 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -62,6 +62,7 @@ "leaflet-providers": "^1.13.0", "leaflet.gridlayer.googlemutant": "^0.13.4", "leaflet.markercluster": "^1.5.3", + "libphonenumber-js": "^1.10.4", "messageformat": "^2.3.0", "moment": "^2.29.1", "moment-timezone": "^0.5.34", diff --git a/ui-ngx/src/app/shared/components/phone-input.component.html b/ui-ngx/src/app/shared/components/phone-input.component.html new file mode 100644 index 0000000000..9001e04ce8 --- /dev/null +++ b/ui-ngx/src/app/shared/components/phone-input.component.html @@ -0,0 +1,51 @@ + + +
+
+
+ {{ flagIcon }} + + + {{country.flag}} + {{country.name + ' +' + country.dialCode }} + + +
+ + phone-input.phone-input-label + + + {{ 'phone-input.phone-input-required' | translate }} + + + {{ 'phone-input.phone-input-validation' | translate }} + + + {{ 'phone-input.phone-input-pattern' | translate }} + + +
+
diff --git a/ui-ngx/src/app/shared/components/phone-input.component.scss b/ui-ngx/src/app/shared/components/phone-input.component.scss new file mode 100644 index 0000000000..0145a13d62 --- /dev/null +++ b/ui-ngx/src/app/shared/components/phone-input.component.scss @@ -0,0 +1,60 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * 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. + */ +:host ::ng-deep { + + .phone-input-container { + display: flex; + align-items: center; + + .phone-input { + width: 100%; + } + } + + .flags-select-container { + display: inline-block; + position: relative; + width: 50px; + height: 100%; + margin-right: 5px; + } + + .flag-container { + position: absolute; + font-size: 20px; + top: 50%; + left: 0; + transform: translate(0, -50%); + } + .country-select { + width: 45px; + height: 30px; + + .country-flag { + font-size: 22px; + padding-right: 10px; + } + + .mat-select-trigger { + height: 100%; + width: 100%; + } + + .mat-select-value { + visibility: hidden; + } + } +} diff --git a/ui-ngx/src/app/shared/components/phone-input.component.ts b/ui-ngx/src/app/shared/components/phone-input.component.ts new file mode 100644 index 0000000000..6618811e19 --- /dev/null +++ b/ui-ngx/src/app/shared/components/phone-input.component.ts @@ -0,0 +1,215 @@ +/// +/// Copyright © 2016-2022 The Thingsboard Authors +/// +/// 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 { Component, forwardRef, Input, OnInit } from '@angular/core'; +import { + ControlValueAccessor, + FormBuilder, + FormControl, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + ValidatorFn, + Validators +} from '@angular/forms'; +import { TranslateService } from '@ngx-translate/core'; +import { Country, CountryData } from '@shared/models/country.models'; +import examples from 'libphonenumber-js/examples.mobile.json'; +import { CountryCode, getExampleNumber, parsePhoneNumberFromString } from 'libphonenumber-js'; +import { phoneNumberPattern } from '@shared/models/settings.models'; +import { Subscription } from 'rxjs'; + +@Component({ + selector: 'tb-phone-input', + templateUrl: './phone-input.component.html', + styleUrls: ['./phone-input.component.scss'], + providers: [ + CountryData, + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PhoneInputComponent), + multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => PhoneInputComponent), + multi: true + } + ] +}) +export class PhoneInputComponent implements OnInit, ControlValueAccessor, Validator { + + @Input() disabled: boolean; + @Input() defaultCountry: CountryCode = 'US'; + @Input() enableFlagsSelect = true; + @Input() required = true; + + allCountries: Array = []; + phonePlaceholder: string; + countryCallingCode: string; + flagIcon: string; + + phoneNumberPattern = phoneNumberPattern; + + private modelValue: string; + public phoneFormGroup: FormGroup; + private valueChange$: Subscription = null; + private propagateChange = (v: any) => { }; + + constructor(private translate: TranslateService, + private fb: FormBuilder, + private countryCodeData: CountryData) { + } + + ngOnInit(): void { + if (this.enableFlagsSelect) { + this.fetchCountryData(); + } + this.phoneFormGroup = this.fb.group({ + country: [this.defaultCountry, []], + phoneNumber: [ + this.countryCallingCode, + this.required ? [Validators.required, Validators.pattern(phoneNumberPattern), this.validatePhoneNumber()] : [] + ] + }); + + this.valueChange$ = this.phoneFormGroup.get('phoneNumber').valueChanges.subscribe(() => { + this.updateModel(); + }); + + this.phoneFormGroup.get('country').valueChanges.subscribe(value => { + if (value) { + const code = this.countryCallingCode; + this.getFlagAndPhoneNumberData(value); + let phoneNumber = this.phoneFormGroup.get('phoneNumber').value; + if (code !== this.countryCallingCode && phoneNumber) { + phoneNumber = phoneNumber.replace(code, this.countryCallingCode); + } else { + phoneNumber = this.countryCallingCode; + } + this.phoneFormGroup.get('phoneNumber').patchValue(phoneNumber); + } + }); + + this.phoneFormGroup.get('phoneNumber').valueChanges.subscribe(value => { + if (value) { + const parsedPhoneNumber = parsePhoneNumberFromString(value); + const country = this.phoneFormGroup.get('country').value; + if (parsedPhoneNumber?.country && parsedPhoneNumber?.country !== country) { + this.phoneFormGroup.get('country').patchValue(parsedPhoneNumber.country, {emitEvent: true}); + } + } + }); + } + + ngOnDestroy() { + if (this.valueChange$) { + this.valueChange$.unsubscribe(); + } + } + + getFlagAndPhoneNumberData(country) { + if (this.enableFlagsSelect) { + this.flagIcon = this.getFlagIcon(country); + } + this.getPhoneNumberData(country); + } + + getPhoneNumberData(country): void { + const phoneData = getExampleNumber(country, examples); + this.phonePlaceholder = phoneData.number; + this.countryCallingCode = '+' + phoneData.countryCallingCode; + } + + getFlagIcon(countryCode) { + const base = 127462 - 65; + return String.fromCodePoint(...countryCode.split('').map(country => base + country.charCodeAt(0))); + } + + validatePhoneNumber(): ValidatorFn { + return (c: FormControl) => { + const phoneNumber = c.value; + if (phoneNumber) { + const parsedPhoneNumber = parsePhoneNumberFromString(phoneNumber); + if (!parsedPhoneNumber?.isValid() || !parsedPhoneNumber?.isPossible()) { + return { + invalidPhoneNumber: { + valid: false + } + }; + } + } + return null; + }; + } + + validate(): ValidationErrors | null { + return this.phoneFormGroup.get('phoneNumber').valid ? null : { + phoneFormGroup: false + }; + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.phoneFormGroup.disable({emitEvent: false}); + } else { + this.phoneFormGroup.enable({emitEvent: false}); + } + } + + protected fetchCountryData(): void { + this.allCountries = []; + this.countryCodeData.allCountries.forEach((c) => { + const cc = c[1]; + const country: Country = { + name: c[0].toString(), + iso2: c[1].toString(), + dialCode: c[2].toString(), + flag: this.getFlagIcon(cc), + }; + + this.allCountries.push(country); + }); + } + + writeValue(phoneNumber): void { + this.modelValue = phoneNumber; + const country = phoneNumber ? parsePhoneNumberFromString(phoneNumber)?.country : this.defaultCountry; + this.getFlagAndPhoneNumberData(country); + this.phoneFormGroup.patchValue({phoneNumber, country}, {emitEvent: !phoneNumber}); + } + + private updateModel() { + const phoneNumber = this.phoneFormGroup.get('phoneNumber'); + if (phoneNumber.valid && this.modelValue !== phoneNumber.value) { + this.modelValue = phoneNumber.value; + this.propagateChange(this.modelValue); + } else { + this.propagateChange(null); + } + } + +} diff --git a/ui-ngx/src/app/shared/models/country.models.ts b/ui-ngx/src/app/shared/models/country.models.ts new file mode 100644 index 0000000000..a4ed4d38d9 --- /dev/null +++ b/ui-ngx/src/app/shared/models/country.models.ts @@ -0,0 +1,1587 @@ +import { Injectable } from '@angular/core'; + +export interface Country { + name: string; + iso2: string; + dialCode: string; + areaCodes?: string[]; + flag: string; +} + +export enum SearchCountryField { + DialCode = 'dialCode', + Iso2 = 'iso2', + Name = 'name', + All = 'all' +} + + +export enum CountryISO{ + Afghanistan = 'AF', + Albania = 'AL', + Algeria = 'DZ', + AmericanSamoa = 'AS', + Andorra = 'AD', + Angola = 'AO', + Anguilla = 'AI', + AntiguaAndBarbuda = 'AG', + Argentina = 'AR', + Armenia = 'AM', + Aruba = 'AW', + Australia = 'AU', + Austria = 'AT', + Azerbaijan = 'AZ', + Bahamas = 'BS', + Bahrain = 'BH', + Bangladesh = 'BD', + Barbados = 'BB', + Belarus = 'BY', + Belgium = 'BE', + Belize = 'BZ', + Benin = 'BJ', + Bermuda = 'BM', + Bhutan = 'BT', + Bolivia = 'BO', + BosniaAndHerzegovina = 'BA', + Botswana = 'BW', + Brazil = 'BR', + BritishIndianOceanTerritory = 'IO', + BritishVirginIslands = 'VG', + Brunei = 'BN', + Bulgaria = 'BG', + BurkinaFaso = 'BF', + Burundi = 'BI', + Cambodia = 'KH', + Cameroon = 'CM', + Canada = 'CA', + CapeVerde = 'CV', + CaribbeanNetherlands = 'BQ', + CaymanIslands = 'KY', + CentralAfricanRepublic = 'CF', + Chad = 'TD', + Chile = 'CL', + China = 'CN', + ChristmasIsland = 'CX', + Cocos = 'CC', + Colombia = 'CC', + Comoros = 'KM', + CongoDRCJamhuriYaKidemokrasiaYaKongo = 'CD', + CongoRepublicCongoBrazzaville = 'CG', + CookIslands = 'CK', + CostaRica = 'CR', + CôteDIvoire = 'CI', + Croatia = 'HR', + Cuba = 'CU', + Curaçao = 'CW', + Cyprus = 'CY', + CzechRepublic = 'CZ', + Denmark = 'DK', + Djibouti = 'DJ', + Dominica = 'DM', + DominicanRepublic = 'DO', + Ecuador = 'EC', + Egypt = 'EG', + ElSalvador = 'SV', + EquatorialGuinea = 'GQ', + Eritrea = 'ER', + Estonia = 'EE', + Ethiopia = 'ET', + FalklandIslands = 'FK', + FaroeIslands = 'FO', + Fiji = 'FJ', + Finland = 'FI', + France = 'FR', + FrenchGuiana = 'GF', + FrenchPolynesia = 'PF', + Gabon = 'GA', + Gambia = 'GM', + Georgia = 'GE', + Germany = 'DE', + Ghana = 'GH', + Gibraltar = 'GI', + Greece = 'GR', + Greenland = 'GL', + Grenada = 'GD', + Guadeloupe = 'GP', + Guam = 'GU', + Guatemala = 'GT', + Guernsey = 'GG', + Guinea = 'GN', + GuineaBissau = 'GW', + Guyana = 'GY', + Haiti = 'HT', + Honduras = 'HN', + HongKong = 'HK', + Hungary = 'HU', + Iceland = 'IS', + India = 'IN', + Indonesia = 'ID', + Iran = 'IR', + Iraq = 'IQ', + Ireland = 'IE', + IsleOfMan = 'IM', + Israel = 'IL', + Italy = 'IT', + Jamaica = 'JM', + Japan = 'JP', + Jersey = 'JE', + Jordan = 'JO', + Kazakhstan = 'KZ', + Kenya = 'KE', + Kiribati = 'KI', + Kosovo = 'XK', + Kuwait = 'KW', + Kyrgyzstan = 'KG', + Laos = 'LA', + Latvia = 'LV', + Lebanon = 'LB', + Lesotho = 'LS', + Liberia = 'LR', + Libya = 'LY', + Liechtenstein = 'LI', + Lithuania = 'LT', + Luxembourg = 'LU', + Macau = 'MO', + Macedonia = 'MK', + Madagascar = 'MG', + Malawi = 'MW', + Malaysia = 'MY', + Maldives = 'MV', + Mali = 'ML', + Malta = 'MT', + MarshallIslands = 'MH', + Martinique = 'MQ', + Mauritania = 'MR', + Mauritius = 'MU', + Mayotte = 'YT', + Mexico = 'MX', + Micronesia = 'FM', + Moldova = 'MD', + Monaco = 'MC', + Mongolia = 'MN', + Montenegro = 'ME', + Montserrat = 'MS', + Morocco = 'MA', + Mozambique = 'MZ', + Myanmar = 'MM', + Namibia = 'NA', + Nauru = 'NR', + Nepal = 'NP', + Netherlands = 'NL', + NewCaledonia = 'NC', + NewZealand = 'NZ', + Nicaragua = 'NI', + Niger = 'NE', + Nigeria = 'NG', + Niue = 'NU', + NorfolkIsland = 'NF', + NorthKorea = 'KP', + NorthernMarianaIslands = 'MP', + Norway = 'NO', + Oman = 'OM', + Pakistan = 'PK', + Palau = 'PW', + Palestine = 'PS', + Panama = 'PA', + PapuaNewGuinea = 'PG', + Paraguay = 'PY', + Peru = 'PE', + Philippines = 'PH', + Poland = 'PL', + Portugal = 'PT', + PuertoRico = 'PR', + Qatar = 'QA', + Réunion = 'RE', + Romania = 'RO', + Russia = 'RU', + Rwanda = 'RW', + SaintBarthélemy = 'BL', + SaintHelena = 'SH', + SaintKittsAndNevis = 'KN', + SaintLucia = 'LC', + SaintMartin = 'MF', + SaintPierreAndMiquelon = 'PM', + SaintVincentAndTheGrenadines = 'VC', + Samoa = 'WS', + SanMarino = 'SM', + SãoToméAndPríncipe = 'ST', + SaudiArabia = 'SA', + Senegal = 'SN', + Serbia = 'RS', + Seychelles = 'SC', + SierraLeone = 'SL', + Singapore = 'SG', + SintMaarten = 'SX', + Slovakia = 'SK', + Slovenia = 'SI', + SolomonIslands = 'SB', + Somalia = 'SO', + SouthAfrica = 'ZA', + SouthKorea = 'KR', + SouthSudan = 'SS', + Spain = 'ES', + SriLanka = 'LK', + Sudan = 'SD', + Suriname = 'SR', + SvalbardAndJanMayen = 'SJ', + Swaziland = 'SZ', + Sweden = 'SE', + Switzerland = 'CH', + Syria = 'SY', + Taiwan = 'TW', + Tajikistan = 'TJ', + Tanzania = 'TZ', + Thailand = 'TH', + TimorLeste = 'TL', + Togo = 'TG', + Tokelau = 'TK', + Tonga = 'TO', + TrinidadAndTobago = 'TT', + Tunisia = 'TN', + Turkey = 'TR', + Turkmenistan = 'TM', + TurksAndCaicosIslands = 'TC', + Tuvalu = 'TV', + USVirginIslands = 'VI', + Uganda = 'UG', + Ukraine = 'UA', + UnitedArabEmirates = 'AE', + UnitedKingdom = 'GB', + UnitedStates = 'US', + Uruguay = 'UY', + Uzbekistan = 'UZ', + Vanuatu = 'VU', + VaticanCity = 'VA', + Venezuela = 'VE', + Vietnam = 'VN', + WallisAndFutuna = 'WF', + WesternSahara = 'EH', + Yemen = 'YE', + Zambia = 'ZM', + Zimbabwe = 'ZW', + ÅlandIslands = 'AX', +} + +@Injectable() +export class CountryData { + public allCountries = [ + [ + 'Afghanistan', + CountryISO.Afghanistan, + '93' + ], + [ + 'Albania', + CountryISO.Albania, + '355' + ], + [ + 'Algeria', + CountryISO.Algeria, + '213' + ], + [ + 'American Samoa', + CountryISO.AmericanSamoa, + '1', + 1, + [ + '684', + ] + ], + [ + 'Andorra', + CountryISO.Andorra, + '376' + ], + [ + 'Angola', + CountryISO.Angola, + '244' + ], + [ + 'Anguilla', + CountryISO.Anguilla, + '1', + 1, + [ + '264', + ] + ], + [ + 'Antigua and Barbuda', + CountryISO.AntiguaAndBarbuda, + '1', + 1, + [ + '268', + ] + ], + [ + 'Argentina', + CountryISO.Argentina, + '54' + ], + [ + 'Armenia', + CountryISO.Armenia, + '374' + ], + [ + 'Aruba', + CountryISO.Aruba, + '297' + ], + [ + 'Australia', + CountryISO.Australia, + '61', + 0 + ], + [ + 'Austria', + CountryISO.Austria, + '43' + ], + [ + 'Azerbaijan', + CountryISO.Azerbaijan, + '994' + ], + [ + 'Bahamas', + CountryISO.Bahamas, + '1', + 1, + [ + '242', + ] + ], + [ + 'Bahrain', + CountryISO.Bahrain, + '973' + ], + [ + 'Bangladesh', + CountryISO.Bangladesh, + '880' + ], + [ + 'Barbados', + CountryISO.Barbados, + '1', + 1, + [ + '246', + ] + ], + [ + 'Belarus', + CountryISO.Belarus, + '375' + ], + [ + 'Belgium', + CountryISO.Belgium, + '32' + ], + [ + 'Belize', + CountryISO.Belize, + '501' + ], + [ + 'Benin', + CountryISO.Benin, + '229' + ], + [ + 'Bermuda', + CountryISO.Bermuda, + '1', + 1, + [ + '441', + ] + ], + [ + 'Bhutan', + CountryISO.Bhutan, + '975' + ], + [ + 'Bolivia', + CountryISO.Bolivia, + '591' + ], + [ + 'Bosnia and Herzegovina', + CountryISO.BosniaAndHerzegovina, + '387' + ], + [ + 'Botswana', + CountryISO.Botswana, + '267' + ], + [ + 'Brazil', + CountryISO.Brazil, + '55' + ], + [ + 'British Indian Ocean Territory', + CountryISO.BritishIndianOceanTerritory, + '246' + ], + [ + 'British Virgin Islands', + CountryISO.BritishVirginIslands, + '1', + 1, + [ + '284', + ] + ], + [ + 'Brunei', + CountryISO.Brunei, + '673' + ], + [ + 'Bulgaria', + CountryISO.Bulgaria, + '359' + ], + [ + 'Burkina Faso', + CountryISO.BurkinaFaso, + '226' + ], + [ + 'Burundi', + CountryISO.Burundi, + '257' + ], + [ + 'Cambodia', + CountryISO.Cambodia, + '855' + ], + [ + 'Cameroon', + CountryISO.Cameroon, + '237' + ], + [ + 'Canada', + CountryISO.Canada, + '1', + 1, + [ + '204', '226', '236', '249', '250', '289', '306', '343', '365', '387', '403', '416', + '418', '431', '437', '438', '450', '506', '514', '519', '548', '579', '581', '587', + '604', '613', '639', '647', '672', '705', '709', '742', '778', '780', '782', '807', + '819', '825', '867', '873', '902', '905' + ] + ], + [ + 'Cape Verde', + CountryISO.CapeVerde, + '238' + ], + [ + 'Caribbean Netherlands', + CountryISO.CaribbeanNetherlands, + '599', + 1 + ], + [ + 'Cayman Islands', + CountryISO.CaymanIslands, + '1', + 1, + [ + '345', + ] + ], + [ + 'Central African Republic', + CountryISO.CentralAfricanRepublic, + '236' + ], + [ + 'Chad', + CountryISO.Chad, + '235' + ], + [ + 'Chile', + CountryISO.Chile, + '56' + ], + [ + 'China', + CountryISO.China, + '86' + ], + [ + 'Christmas Island', + CountryISO.ChristmasIsland, + '61', + 2 + ], + [ + 'Cocos Islands', + CountryISO.Cocos, + '61', + 1 + ], + [ + 'Colombia', + CountryISO.Colombia, + '57' + ], + [ + 'Comoros', + CountryISO.Comoros, + '269' + ], + [ + 'Congo-Kinshasa', + CountryISO.CongoDRCJamhuriYaKidemokrasiaYaKongo, + '243' + ], + [ + 'Congo-Brazzaville', + CountryISO.CongoRepublicCongoBrazzaville, + '242' + ], + [ + 'Cook Islands', + CountryISO.CookIslands, + '682' + ], + [ + 'Costa Rica', + CountryISO.CostaRica, + '506' + ], + [ + 'Côte d’Ivoire', + CountryISO.CôteDIvoire, + '225' + ], + [ + 'Croatia', + CountryISO.Croatia, + '385' + ], + [ + 'Cuba', + CountryISO.Cuba, + '53' + ], + [ + 'Curaçao', + CountryISO.Curaçao, + '599', + 0 + ], + [ + 'Cyprus', + CountryISO.Cyprus, + '357' + ], + [ + 'Czech Republic', + CountryISO.CzechRepublic, + '420' + ], + [ + 'Denmark', + CountryISO.Denmark, + '45' + ], + [ + 'Djibouti', + CountryISO.Djibouti, + '253' + ], + [ + 'Dominica', + CountryISO.Dominica, + '1767' + ], + [ + 'Dominican Republic', + CountryISO.DominicanRepublic, + '1', + 2, + ['809', '829', '849'] + ], + [ + 'Ecuador', + CountryISO.Ecuador, + '593' + ], + [ + 'Egypt', + CountryISO.Egypt, + '20' + ], + [ + 'El Salvador', + CountryISO.ElSalvador, + '503' + ], + [ + 'Equatorial Guinea', + CountryISO.EquatorialGuinea, + '240' + ], + [ + 'Eritrea', + CountryISO.Eritrea, + '291' + ], + [ + 'Estonia', + CountryISO.Estonia, + '372' + ], + [ + 'Ethiopia', + CountryISO.Ethiopia, + '251' + ], + [ + 'Falkland Islands', + CountryISO.FalklandIslands, + '500' + ], + [ + 'Faroe Islands', + CountryISO.FaroeIslands, + '298' + ], + [ + 'Fiji', + CountryISO.Fiji, + '679' + ], + [ + 'Finland', + CountryISO.Finland, + '358', + 0 + ], + [ + 'France', + CountryISO.France, + '33' + ], + [ + 'French Guiana', + CountryISO.FrenchGuiana, + '594' + ], + [ + 'French Polynesia', + CountryISO.FrenchPolynesia, + '689' + ], + [ + 'Gabon', + CountryISO.Gabon, + '241' + ], + [ + 'Gambia', + CountryISO.Gambia, + '220' + ], + [ + 'Georgia', + CountryISO.Georgia, + '995' + ], + [ + 'Germany', + CountryISO.Germany, + '49' + ], + [ + 'Ghana', + CountryISO.Ghana, + '233' + ], + [ + 'Gibraltar', + CountryISO.Gibraltar, + '350' + ], + [ + 'Greece', + CountryISO.Greece, + '30' + ], + [ + 'Greenland', + CountryISO.Greenland, + '299' + ], + [ + 'Grenada', + CountryISO.Grenada, + '1473' + ], + [ + 'Guadeloupe', + CountryISO.Guadeloupe, + '590', + 0 + ], + [ + 'Guam', + CountryISO.Guam, + '1', + 1, + [ + '671', + ] + ], + [ + 'Guatemala', + CountryISO.Guatemala, + '502' + ], + [ + 'Guernsey', + CountryISO.Guernsey, + '44', + 1, + [1481] + ], + [ + 'Guinea', + CountryISO.Guinea, + '224' + ], + [ + 'Guinea-Bissau', + CountryISO.GuineaBissau, + '245' + ], + [ + 'Guyana', + CountryISO.Guyana, + '592' + ], + [ + 'Haiti', + CountryISO.Haiti, + '509' + ], + [ + 'Honduras', + CountryISO.Honduras, + '504' + ], + [ + 'Hong Kong', + CountryISO.HongKong, + '852' + ], + [ + 'Hungary', + CountryISO.Hungary, + '36' + ], + [ + 'Iceland', + CountryISO.Iceland, + '354' + ], + [ + 'India', + CountryISO.India, + '91' + ], + [ + 'Indonesia', + CountryISO.Indonesia, + '62' + ], + [ + 'Iran', + CountryISO.Iran, + '98' + ], + [ + 'Iraq', + CountryISO.Iraq, + '964' + ], + [ + 'Ireland', + CountryISO.Ireland, + '353' + ], + [ + 'Isle of Man', + CountryISO.IsleOfMan, + '44', + 2, + [1624] + ], + [ + 'Israel', + CountryISO.Israel, + '972' + ], + [ + 'Italy', + CountryISO.Italy, + '39', + 0 + ], + [ + 'Jamaica', + CountryISO.Jamaica, + '1', + 1, + [ + '876', + ] + ], + [ + 'Japan', + CountryISO.Japan, + '81' + ], + [ + 'Jersey', + CountryISO.Jersey, + '44', + 3, + [1534] + ], + [ + 'Jordan', + CountryISO.Jordan, + '962' + ], + [ + 'Kazakhstan', + CountryISO.Kazakhstan, + '7', + 1 + ], + [ + 'Kenya', + CountryISO.Kenya, + '254' + ], + [ + 'Kiribati', + CountryISO.Kiribati, + '686' + ], + [ + 'Kosovo', + CountryISO.Kosovo, + '383' + ], + [ + 'Kuwait', + CountryISO.Kuwait, + '965' + ], + [ + 'Kyrgyzstan', + CountryISO.Kyrgyzstan, + '996' + ], + [ + 'Laos', + CountryISO.Laos, + '856' + ], + [ + 'Latvia', + CountryISO.Latvia, + '371' + ], + [ + 'Lebanon', + CountryISO.Lebanon, + '961' + ], + [ + 'Lesotho', + CountryISO.Lesotho, + '266' + ], + [ + 'Liberia', + CountryISO.Liberia, + '231' + ], + [ + 'Libya', + CountryISO.Libya, + '218' + ], + [ + 'Liechtenstein', + CountryISO.Liechtenstein, + '423' + ], + [ + 'Lithuania', + CountryISO.Lithuania, + '370' + ], + [ + 'Luxembourg', + CountryISO.Luxembourg, + '352' + ], + [ + 'Macau', + CountryISO.Macau, + '853' + ], + [ + 'Macedonia', + CountryISO.Macedonia, + '389' + ], + [ + 'Madagascar', + CountryISO.Madagascar, + '261' + ], + [ + 'Malawi', + CountryISO.Malawi, + '265' + ], + [ + 'Malaysia', + CountryISO.Malaysia, + '60' + ], + [ + 'Maldives', + CountryISO.Maldives, + '960' + ], + [ + 'Mali', + CountryISO.Mali, + '223' + ], + [ + 'Malta', + CountryISO.Malta, + '356' + ], + [ + 'Marshall Islands', + CountryISO.MarshallIslands, + '692' + ], + [ + 'Martinique', + CountryISO.Martinique, + '596' + ], + [ + 'Mauritania', + CountryISO.Mauritania, + '222' + ], + [ + 'Mauritius', + CountryISO.Mauritius, + '230' + ], + [ + 'Mayotte', + CountryISO.Mayotte, + '262', + 1 + ], + [ + 'Mexico', + CountryISO.Mexico, + '52' + ], + [ + 'Micronesia', + CountryISO.Micronesia, + '691' + ], + [ + 'Moldova', + CountryISO.Moldova, + '373' + ], + [ + 'Monaco', + CountryISO.Monaco, + '377' + ], + [ + 'Mongolia', + CountryISO.Mongolia, + '976' + ], + [ + 'Montenegro', + CountryISO.Montenegro, + '382' + ], + [ + 'Montserrat', + CountryISO.Montserrat, + '1', + 1, + [ + '664', + ] + ], + [ + 'Morocco', + CountryISO.Morocco, + '212', + 0 + ], + [ + 'Mozambique', + CountryISO.Mozambique, + '258' + ], + [ + 'Myanmar', + CountryISO.Myanmar, + '95' + ], + [ + 'Namibia', + CountryISO.Namibia, + '264' + ], + [ + 'Nauru', + CountryISO.Nauru, + '674' + ], + [ + 'Nepal', + CountryISO.Nepal, + '977' + ], + [ + 'Netherlands', + CountryISO.Netherlands, + '31' + ], + [ + 'New Caledonia', + CountryISO.NewCaledonia, + '687' + ], + [ + 'New Zealand', + CountryISO.NewZealand, + '64' + ], + [ + 'Nicaragua', + CountryISO.Nicaragua, + '505' + ], + [ + 'Niger', + CountryISO.Niger, + '227' + ], + [ + 'Nigeria', + CountryISO.Nigeria, + '234' + ], + [ + 'Niue', + CountryISO.Niue, + '683' + ], + [ + 'Norfolk Island', + CountryISO.NorfolkIsland, + '672' + ], + [ + 'North Korea', + CountryISO.NorthKorea, + '850' + ], + [ + 'Northern Mariana Islands', + CountryISO.NorthernMarianaIslands, + '1670' + ], + [ + 'Norway', + CountryISO.Norway, + '47', + 0 + ], + [ + 'Oman', + CountryISO.Oman, + '968' + ], + [ + 'Pakistan', + CountryISO.Pakistan, + '92' + ], + [ + 'Palau', + CountryISO.Palau, + '680' + ], + [ + 'Palestine', + CountryISO.Palestine, + '970' + ], + [ + 'Panama', + CountryISO.Panama, + '507' + ], + [ + 'Papua New Guinea', + CountryISO.PapuaNewGuinea, + '675' + ], + [ + 'Paraguay', + CountryISO.Paraguay, + '595' + ], + [ + 'Peru', + CountryISO.Peru, + '51' + ], + [ + 'Philippines', + CountryISO.Philippines, + '63' + ], + [ + 'Poland', + CountryISO.Poland, + '48' + ], + [ + 'Portugal', + CountryISO.Portugal, + '351' + ], + [ + 'Puerto Rico', + CountryISO.PuertoRico, + '1', + 3, + ['787', '939'] + ], + [ + 'Qatar', + CountryISO.Qatar, + '974' + ], + [ + 'Réunion', + CountryISO.Réunion, + '262', + 0 + ], + [ + 'Romania', + CountryISO.Romania, + '40' + ], + [ + 'Russia', + CountryISO.Russia, + '7', + 0 + ], + [ + 'Rwanda', + CountryISO.Rwanda, + '250' + ], + [ + 'Saint Barthélemy', + CountryISO.SaintBarthélemy, + '590', + 1 + ], + [ + 'Saint Helena', + CountryISO.SaintHelena, + '290' + ], + [ + 'Saint Kitts and Nevis', + CountryISO.SaintKittsAndNevis, + '1869' + ], + [ + 'Saint Lucia', + CountryISO.SaintLucia, + '1', + 1, + [ + '758', + ] + ], + [ + 'Saint Martin', + CountryISO.SaintMartin, + '590', + 2 + ], + [ + 'Saint Pierre and Miquelon', + CountryISO.SaintPierreAndMiquelon, + '508' + ], + [ + 'Saint Vincent and the Grenadines', + CountryISO.SaintVincentAndTheGrenadines, + '1', + 1, + [ + '784', + ] + ], + [ + 'Samoa', + CountryISO.Samoa, + '685' + ], + [ + 'San Marino', + CountryISO.SanMarino, + '378' + ], + [ + 'São Tomé and Príncipe', + CountryISO.SãoToméAndPríncipe, + '239' + ], + [ + 'Saudi Arabia', + CountryISO.SaudiArabia, + '966' + ], + [ + 'Senegal', + CountryISO.Senegal, + '221' + ], + [ + 'Serbia', + CountryISO.Serbia, + '381' + ], + [ + 'Seychelles', + CountryISO.Seychelles, + '248' + ], + [ + 'Sierra Leone', + CountryISO.SierraLeone, + '232' + ], + [ + 'Singapore', + CountryISO.Singapore, + '65' + ], + [ + 'Sint Maarten', + CountryISO.SintMaarten, + '1', + 1, + [ + '721', + ] + ], + [ + 'Slovakia', + CountryISO.Slovakia, + '421' + ], + [ + 'Slovenia', + CountryISO.Slovenia, + '386' + ], + [ + 'Solomon Islands', + CountryISO.SolomonIslands, + '677' + ], + [ + 'Somalia', + CountryISO.Somalia, + '252' + ], + [ + 'South Africa', + CountryISO.SouthAfrica, + '27' + ], + [ + 'South Korea', + CountryISO.SouthKorea, + '82' + ], + [ + 'South Sudan', + CountryISO.SouthSudan, + '211' + ], + [ + 'Spain', + CountryISO.Spain, + '34' + ], + [ + 'Sri Lanka', + CountryISO.SriLanka, + '94' + ], + [ + 'Sudan', + CountryISO.Sudan, + '249' + ], + [ + 'Suriname', + CountryISO.Suriname, + '597' + ], + [ + 'Svalbard and Jan Mayen', + CountryISO.SvalbardAndJanMayen, + '47', + 1 + ], + [ + 'Swaziland', + CountryISO.Swaziland, + '268' + ], + [ + 'Sweden', + CountryISO.Sweden, + '46' + ], + [ + 'Switzerland', + CountryISO.Switzerland, + '41' + ], + [ + 'Syria', + CountryISO.Syria, + '963' + ], + [ + 'Taiwan', + CountryISO.Taiwan, + '886' + ], + [ + 'Tajikistan', + CountryISO.Tajikistan, + '992' + ], + [ + 'Tanzania', + CountryISO.Tanzania, + '255' + ], + [ + 'Thailand', + CountryISO.Thailand, + '66' + ], + [ + 'Timor-Leste', + CountryISO.TimorLeste, + '670' + ], + [ + 'Togo', + CountryISO.Togo, + '228' + ], + [ + 'Tokelau', + CountryISO.Tokelau, + '690' + ], + [ + 'Tonga', + CountryISO.Tonga, + '676' + ], + [ + 'Trinidad and Tobago', + CountryISO.TrinidadAndTobago, + '1', + 1, + [ + '868', + ] + ], + [ + 'Tunisia', + CountryISO.Tunisia, + '216' + ], + [ + 'Turkey', + CountryISO.Turkey, + '90' + ], + [ + 'Turkmenistan', + CountryISO.Turkmenistan, + '993' + ], + [ + 'Turks and Caicos Islands', + CountryISO.TurksAndCaicosIslands, + '1649' + ], + [ + 'Tuvalu', + CountryISO.Tuvalu, + '688' + ], + [ + 'U.S. Virgin Islands', + CountryISO.USVirginIslands, + '1', + 1, + [ + '340', + ] + ], + [ + 'Uganda', + CountryISO.Uganda, + '256' + ], + [ + 'Ukraine', + CountryISO.Ukraine, + '380' + ], + [ + 'United Arab Emirates', + CountryISO.UnitedArabEmirates, + '971' + ], + [ + 'United Kingdom', + CountryISO.UnitedKingdom, + '44', + 0 + ], + [ + 'United States', + CountryISO.UnitedStates, + '1', + 0 + ], + [ + 'Uruguay', + CountryISO.Uruguay, + '598' + ], + [ + 'Uzbekistan', + CountryISO.Uzbekistan, + '998' + ], + [ + 'Vanuatu', + CountryISO.Vanuatu, + '678' + ], + [ + 'Vatican City', + CountryISO.VaticanCity, + '39', + 1 + ], + [ + 'Venezuela', + CountryISO.Venezuela, + '58' + ], + [ + 'Vietnam', + CountryISO.Vietnam, + '84' + ], + [ + 'Wallis and Futuna', + CountryISO.WallisAndFutuna, + '681' + ], + [ + 'Western Sahara', + CountryISO.WesternSahara, + '212', + 1 + ], + [ + 'Yemen', + CountryISO.Yemen, + '967' + ], + [ + 'Zambia', + CountryISO.Zambia, + '260' + ], + [ + 'Zimbabwe', + CountryISO.Zimbabwe, + '263' + ], + [ + 'Åland Islands', + CountryISO.ÅlandIslands, + '358', + 1 + ] + ]; +} diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index a356fa5921..706ffb16a0 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -159,6 +159,7 @@ import { TbMarkdownComponent } from '@shared/components/markdown.component'; import { ProtobufContentComponent } from '@shared/components/protobuf-content.component'; import { CssComponent } from '@shared/components/css.component'; import { SafePipe } from '@shared/pipe/safe.pipe'; +import { PhoneInputComponent } from '@shared/components/phone-input.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -277,7 +278,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) WidgetsBundleSearchComponent, CopyButtonComponent, TogglePasswordComponent, - ProtobufContentComponent + ProtobufContentComponent, + PhoneInputComponent ], imports: [ CommonModule, @@ -472,7 +474,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) WidgetsBundleSearchComponent, CopyButtonComponent, TogglePasswordComponent, - ProtobufContentComponent + ProtobufContentComponent, + PhoneInputComponent ] }) export class SharedModule { } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index aab433c992..050080d5ba 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3351,6 +3351,12 @@ "material-icons": "Material icons", "show-all": "Show all icons" }, + "phone-input": { + "phone-input-label": "Phone number", + "phone-input-required": "Phone number is required", + "phone-input-validation": "Phone number is invalid or not possible", + "phone-input-pattern": "Invalid phone number. Should be in E.164 format, ex. +19995550123." + }, "custom": { "widget-action": { "action-cell-button": "Action cell button", diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index 0aac92b131..45fe658406 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6027,6 +6027,11 @@ less@4.1.1: needle "^2.5.2" source-map "~0.6.0" +libphonenumber-js@^1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.4.tgz#90397f0ed620262570a32244c9fbc389cc417ce4" + integrity sha512-9QWxEk4GW5RDnFzt8UtyRENfFpAN8u7Sbf9wf32tcXY9tdtnz1dKHIBwW2Wnfx8ypXJb9zUnTpK9aQJ/B8AlnA== + license-webpack-plugin@2.3.20: version "2.3.20" resolved "https://registry.yarnpkg.com/license-webpack-plugin/-/license-webpack-plugin-2.3.20.tgz#f51fb674ca31519dbedbe1c7aabc036e5a7f2858"