@wazo/sdk 0.41.2 → 0.42.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/wazo-sdk.js +12 -12
- package/esm/api/confd.js +2 -0
- package/esm/domain/CallerID.js +24 -0
- package/esm/domain/Features.js +7 -1
- package/esm/index.js +1 -0
- package/esm/types/api/confd.d.ts +2 -0
- package/esm/types/api/confd.d.ts.map +1 -1
- package/esm/types/domain/CallerID.d.ts +22 -0
- package/esm/types/domain/CallerID.d.ts.map +1 -0
- package/esm/types/domain/Features.d.ts +2 -0
- package/esm/types/domain/Features.d.ts.map +1 -1
- package/esm/types/index.d.ts +1 -0
- package/esm/types/index.d.ts.map +1 -1
- package/esm/types/simple/index.d.ts +2 -0
- package/esm/types/simple/index.d.ts.map +1 -1
- package/esm/types/utils/PhoneNumberUtil.d.ts +5 -6
- package/esm/types/utils/PhoneNumberUtil.d.ts.map +1 -1
- package/esm/utils/PhoneNumberUtil.js +27 -19
- package/esm/utils/__tests__/PhoneNumberUtil.test.js +23 -6
- package/lib/api/confd.js +2 -0
- package/lib/domain/CallerID.js +27 -0
- package/lib/domain/Features.js +6 -1
- package/lib/index.js +4 -2
- package/lib/types/api/confd.d.ts +2 -0
- package/lib/types/api/confd.d.ts.map +1 -1
- package/lib/types/domain/CallerID.d.ts +22 -0
- package/lib/types/domain/CallerID.d.ts.map +1 -0
- package/lib/types/domain/Features.d.ts +2 -0
- package/lib/types/domain/Features.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/simple/index.d.ts +2 -0
- package/lib/types/simple/index.d.ts.map +1 -1
- package/lib/types/utils/PhoneNumberUtil.d.ts +5 -6
- package/lib/types/utils/PhoneNumberUtil.d.ts.map +1 -1
- package/lib/utils/PhoneNumberUtil.js +28 -25
- package/lib/utils/__tests__/PhoneNumberUtil.test.js +22 -5
- package/package.json +2 -3
- package/src/api/confd.ts +3 -0
- package/src/domain/CallerID.ts +49 -0
- package/src/domain/Features.ts +9 -1
- package/src/index.ts +1 -0
- package/src/utils/PhoneNumberUtil.ts +31 -24
- package/src/utils/__tests__/PhoneNumberUtil.test.ts +31 -6
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
declare const
|
|
3
|
-
declare const
|
|
4
|
-
declare const getDisplayableNumber: (rawNumber: string, country: string, asYouType?: boolean) => string;
|
|
1
|
+
import { CountryCode } from 'libphonenumber-js';
|
|
2
|
+
declare const guessParsePhoneNumber: (number: string, defaultCountry?: CountryCode, guessingCountries?: CountryCode[]) => import("libphonenumber-js").PhoneNumber | undefined;
|
|
3
|
+
declare const getDisplayableNumber: (rawNumber: string, country: CountryCode, asYouType?: boolean, guessingCountries?: CountryCode[] | undefined) => string;
|
|
5
4
|
declare const parsePhoneNumber: (phoneNumber: string) => string;
|
|
6
|
-
declare const getCallableNumber: (number: string, country?:
|
|
7
|
-
export {
|
|
5
|
+
declare const getCallableNumber: (number: string, country?: CountryCode) => string;
|
|
6
|
+
export { parsePhoneNumber, getDisplayableNumber, guessParsePhoneNumber, getCallableNumber, type CountryCode };
|
|
8
7
|
//# sourceMappingURL=PhoneNumberUtil.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PhoneNumberUtil.d.ts","sourceRoot":"","sources":["../../../src/utils/PhoneNumberUtil.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"PhoneNumberUtil.d.ts","sourceRoot":"","sources":["../../../src/utils/PhoneNumberUtil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsD,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAsBpG,QAAA,MAAM,qBAAqB,WAAY,MAAM,mBAAmB,WAAW,sBAAqB,WAAW,EAAE,wDAc5G,CAAC;AAEF,QAAA,MAAM,oBAAoB,cAAe,MAAM,WAAW,WAAW,2CAAwC,WAAW,EAAE,GAAG,SAAS,KAAgC,MA6BrK,CAAC;AAEF,QAAA,MAAM,gBAAgB,gBAAiB,MAAM,KAAG,MAAoD,CAAC;AAErG,QAAA,MAAM,iBAAiB,WAAY,MAAM,YAAY,WAAW,KAAG,MAOlE,CAAC;AAEF,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,CAAC"}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getCallableNumber = exports.
|
|
7
|
-
const
|
|
8
|
-
const PhoneNumberUtil = google_libphonenumber_1.default.PhoneNumberUtil.getInstance();
|
|
9
|
-
exports.PhoneNumberUtil = PhoneNumberUtil;
|
|
10
|
-
const { PhoneNumberFormat, AsYouTypeFormatter, } = google_libphonenumber_1.default;
|
|
11
|
-
exports.PhoneNumberFormat = PhoneNumberFormat;
|
|
12
|
-
exports.AsYouTypeFormatter = AsYouTypeFormatter;
|
|
3
|
+
exports.getCallableNumber = exports.guessParsePhoneNumber = exports.getDisplayableNumber = exports.parsePhoneNumber = void 0;
|
|
4
|
+
const libphonenumber_js_1 = require("libphonenumber-js");
|
|
13
5
|
// eslint-disable-next-line
|
|
14
6
|
const EXTRA_CHAR_REGEXP = /[^+*\d]/g;
|
|
7
|
+
const DEFAULT_GUESSING_COUNTRIES = ['US', 'FR', 'GB', 'AU'];
|
|
15
8
|
const shouldBeFormatted = (number) => {
|
|
16
9
|
if (!number || number.length <= 5) {
|
|
17
10
|
return false;
|
|
@@ -24,7 +17,20 @@ const isSameCountry = (country1, country2) => {
|
|
|
24
17
|
}
|
|
25
18
|
return country1 === country2;
|
|
26
19
|
};
|
|
27
|
-
const
|
|
20
|
+
const guessParsePhoneNumber = (number, defaultCountry, guessingCountries = DEFAULT_GUESSING_COUNTRIES) => {
|
|
21
|
+
const mergedCountries = [...new Set([defaultCountry, ...guessingCountries])].filter(Boolean);
|
|
22
|
+
let parsedNumber;
|
|
23
|
+
for (let i = 0; i < mergedCountries.length; i++) {
|
|
24
|
+
const country = mergedCountries[i];
|
|
25
|
+
parsedNumber = (0, libphonenumber_js_1.parsePhoneNumber)(number, country);
|
|
26
|
+
if (parsedNumber.isValid()) {
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return parsedNumber;
|
|
31
|
+
};
|
|
32
|
+
exports.guessParsePhoneNumber = guessParsePhoneNumber;
|
|
33
|
+
const getDisplayableNumber = (rawNumber, country, asYouType = false, guessingCountries = DEFAULT_GUESSING_COUNTRIES) => {
|
|
28
34
|
if (!rawNumber) {
|
|
29
35
|
return rawNumber;
|
|
30
36
|
}
|
|
@@ -34,20 +40,19 @@ const getDisplayableNumber = (rawNumber, country, asYouType = false) => {
|
|
|
34
40
|
}
|
|
35
41
|
let displayValue = '';
|
|
36
42
|
if (asYouType) {
|
|
37
|
-
|
|
38
|
-
number.split('').forEach(char => {
|
|
39
|
-
displayValue = formatter.inputDigit(char);
|
|
40
|
-
});
|
|
43
|
+
displayValue = new libphonenumber_js_1.AsYouType(country).input(number);
|
|
41
44
|
}
|
|
42
45
|
else {
|
|
43
46
|
try {
|
|
44
|
-
const parsedNumber =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
const parsedNumber = guessParsePhoneNumber(number, country, guessingCountries);
|
|
48
|
+
if (parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()) {
|
|
49
|
+
displayValue = isSameCountry(String(parsedNumber.country), country) ? parsedNumber.formatNational() : parsedNumber.formatInternational();
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
displayValue = rawNumber;
|
|
53
|
+
}
|
|
48
54
|
}
|
|
49
|
-
catch (
|
|
50
|
-
// Avoid to crash when phone number like `0080510` can't be parsed
|
|
55
|
+
catch (error) {
|
|
51
56
|
displayValue = rawNumber;
|
|
52
57
|
}
|
|
53
58
|
}
|
|
@@ -58,10 +63,8 @@ const parsePhoneNumber = (phoneNumber) => phoneNumber.replace(EXTRA_CHAR_REGEXP,
|
|
|
58
63
|
exports.parsePhoneNumber = parsePhoneNumber;
|
|
59
64
|
const getCallableNumber = (number, country) => {
|
|
60
65
|
try {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
return parsePhoneNumber(number);
|
|
66
|
+
const callableNumber = country ? getDisplayableNumber(number, country) : number;
|
|
67
|
+
return parsePhoneNumber(callableNumber);
|
|
65
68
|
}
|
|
66
69
|
catch (_) {
|
|
67
70
|
return number;
|
|
@@ -13,7 +13,7 @@ describe('Formatting phone numbers', () => {
|
|
|
13
13
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+33675456545', 'FR')).toBe('06 75 45 65 45');
|
|
14
14
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0675456545', 'FR')).toBe('06 75 45 65 45');
|
|
15
15
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+33675456545', 'US')).toBe('+33 6 75 45 65 45');
|
|
16
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0675456545', 'US')).toBe('+
|
|
16
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0675456545', 'US')).toBe('+33 6 75 45 65 45');
|
|
17
17
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('4188884356', 'US')).toBe('(418) 888-4356');
|
|
18
18
|
});
|
|
19
19
|
it('should format real phone numbers when typing', () => {
|
|
@@ -21,12 +21,12 @@ describe('Formatting phone numbers', () => {
|
|
|
21
21
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('067545', 'FR', true)).toBe('06 75 45');
|
|
22
22
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+3367545', 'US', true)).toBe('+33 6 75 45');
|
|
23
23
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('067545', 'US', true)).toBe('067545');
|
|
24
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('418808', 'US', true)).toBe('418
|
|
24
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('418808', 'US', true)).toBe('(418) 808');
|
|
25
25
|
});
|
|
26
26
|
it('should use the international number if the country number is different from the given country', () => {
|
|
27
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'FR')).toBe('+20
|
|
28
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+14188004554', 'FR')).toBe('+1 418
|
|
29
|
-
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'EG')).toBe('
|
|
27
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'FR')).toBe('+20 10 05803648');
|
|
28
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('+14188004554', 'FR')).toBe('+1 418 800 4554');
|
|
29
|
+
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('00201005803648', 'EG')).toBe('010 05803648');
|
|
30
30
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('0634543450', 'FR')).toBe('06 34 54 34 50');
|
|
31
31
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('4188034302', 'US')).toBe('(418) 803-4302');
|
|
32
32
|
expect((0, PhoneNumberUtil_1.getDisplayableNumber)('8775863230', 'CA')).toBe('(877) 586-3230');
|
|
@@ -53,3 +53,20 @@ describe('getCallableNumber', () => {
|
|
|
53
53
|
expect((0, PhoneNumberUtil_1.getCallableNumber)('9000')).toBe('9000');
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
|
+
describe('guessParsePhoneNumber', () => {
|
|
57
|
+
it('should guess with default countries', () => {
|
|
58
|
+
const parsedNumber = (0, PhoneNumberUtil_1.guessParsePhoneNumber)('0675456545');
|
|
59
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.country).toBe('FR');
|
|
60
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
it('should guess with specified countries', () => {
|
|
63
|
+
const parsedNumber = (0, PhoneNumberUtil_1.guessParsePhoneNumber)('752097514', undefined, ['JP']);
|
|
64
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.country).toBe('JP');
|
|
65
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
it('should used use defaultCountry has guesser', () => {
|
|
68
|
+
const parsedNumber = (0, PhoneNumberUtil_1.guessParsePhoneNumber)('752097514', 'JP', []);
|
|
69
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.country).toBe('JP');
|
|
70
|
+
expect(parsedNumber === null || parsedNumber === void 0 ? void 0 : parsedNumber.isValid()).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wazo/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0-rc.0",
|
|
4
4
|
"description": "Wazo's JavaScript Software Development Kit.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "lib/types/index.d.ts",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"events": "^3.3.0",
|
|
51
51
|
"fstream": "^1.0.12",
|
|
52
52
|
"getstats": "wazo-platform/getStats#fix_stats_mobile",
|
|
53
|
-
"google-libphonenumber": "^3.2.32",
|
|
54
53
|
"js-base64": "^3.7.7",
|
|
55
54
|
"json-to-graphql-query": "^2.2.5",
|
|
56
55
|
"jsrsasign": "^11.1.0",
|
|
56
|
+
"libphonenumber-js": "^1.10.60",
|
|
57
57
|
"moment": "^2.30.1",
|
|
58
58
|
"reconnecting-websocket": "^4.4.0",
|
|
59
59
|
"sdp-transform": "^2.14.2",
|
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
"@rollup/plugin-terser": "^0.4.4",
|
|
71
71
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
72
72
|
"@types/events": "^3.0.3",
|
|
73
|
-
"@types/google-libphonenumber": "^7.4.30",
|
|
74
73
|
"@types/jest": "^29.5.2",
|
|
75
74
|
"@types/jsrsasign": "^10.5.8",
|
|
76
75
|
"@types/node": "^20.4.0",
|
package/src/api/confd.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ApiRequester from '../utils/api-requester';
|
|
2
2
|
import type { UUID, ListConfdUsersResponse, ListApplicationsResponse } from '../domain/types';
|
|
3
3
|
import type { MeetingCreateArguments, MeetingUpdateArguments } from '../domain/Meeting';
|
|
4
|
+
import CallerID from '../domain/CallerID';
|
|
4
5
|
import Profile from '../domain/Profile';
|
|
5
6
|
import SipLine from '../domain/SipLine';
|
|
6
7
|
import ExternalApp from '../domain/ExternalApp';
|
|
@@ -35,6 +36,7 @@ export interface ConfD {
|
|
|
35
36
|
guestGetMeeting: (meetingUuid: string) => Promise<Meeting>;
|
|
36
37
|
guestAuthorizationRequest: (userUuid: string, meetingUuid: string, username: string) => Promise<any>;
|
|
37
38
|
guestAuthorizationCheck: (userUuid: string, meetingUuid: string, authorizationUuid: string) => Promise<any>;
|
|
39
|
+
getOutgoingCallerIDs: (userUuid: string) => Promise<CallerID[]>;
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
export default ((client: ApiRequester, baseUrl: string): ConfD => ({
|
|
@@ -107,4 +109,5 @@ export default ((client: ApiRequester, baseUrl: string): ConfD => ({
|
|
|
107
109
|
guest_name: username,
|
|
108
110
|
}).then(MeetingAuthorization.parse),
|
|
109
111
|
guestAuthorizationCheck: (userUuid: string, meetingUuid: string, authorizationUuid: string): Promise<any> => client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
|
|
112
|
+
getOutgoingCallerIDs: (userUuid: string): Promise<CallerID[]> => client.get(`${baseUrl}/users/${userUuid}/callerids/outgoing`, null).then(CallerID.parseMany),
|
|
110
113
|
}));
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import newFrom from '../utils/new-from';
|
|
2
|
+
|
|
3
|
+
type Response = {
|
|
4
|
+
number?: string;
|
|
5
|
+
type: 'main' | 'associated' | 'anonymous';
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ListResponse = {
|
|
9
|
+
items: Response[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type Arguments = {
|
|
13
|
+
number?: string;
|
|
14
|
+
type: 'main' | 'associated' | 'anonymous';
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default class CallerID {
|
|
18
|
+
number?: string;
|
|
19
|
+
|
|
20
|
+
idType: 'main' | 'associated' | 'anonymous';
|
|
21
|
+
|
|
22
|
+
type: string;
|
|
23
|
+
|
|
24
|
+
static parse(plain: Response): CallerID {
|
|
25
|
+
return new CallerID({
|
|
26
|
+
number: plain.number,
|
|
27
|
+
type: plain.type,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static parseMany(plain: ListResponse): CallerID[] {
|
|
32
|
+
return plain.items.map(item => CallerID.parse(item));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static newFrom(profile: CallerID) {
|
|
36
|
+
return newFrom(profile, CallerID);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
constructor({
|
|
40
|
+
type,
|
|
41
|
+
number,
|
|
42
|
+
}: Arguments) {
|
|
43
|
+
this.idType = type;
|
|
44
|
+
this.number = number;
|
|
45
|
+
// Useful to compare instead of instanceof with minified code
|
|
46
|
+
this.type = 'CallerID';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
package/src/domain/Features.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import getApiClient from '../service/getApiClient';
|
|
2
2
|
|
|
3
|
-
export const FEATURES = ['chat', 'video', 'call_recording', 'fax', 'mobile_double_call', 'mobile_gsm', 'meeting'];
|
|
3
|
+
export const FEATURES = ['chat', 'video', 'call_recording', 'fax', 'mobile_double_call', 'mobile_gsm', 'meeting', 'caller_id'];
|
|
4
4
|
export const getScopeName = (featureName: string) => `enterprise.app.${featureName}`;
|
|
5
5
|
const scopesToCheck = FEATURES.map(getScopeName); // Handle available features on the engine.
|
|
6
6
|
|
|
@@ -19,6 +19,8 @@ class Features {
|
|
|
19
19
|
|
|
20
20
|
_hasMeeting: boolean;
|
|
21
21
|
|
|
22
|
+
_hasCallerID: boolean;
|
|
23
|
+
|
|
22
24
|
constructor() {
|
|
23
25
|
this._hasChat = true;
|
|
24
26
|
this._hasVideo = true;
|
|
@@ -27,6 +29,7 @@ class Features {
|
|
|
27
29
|
this._hasMobileDoubleCall = true;
|
|
28
30
|
this._hasMobileGsm = true;
|
|
29
31
|
this._hasMeeting = true;
|
|
32
|
+
this._hasCallerID = false;
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
async fetchAccess() {
|
|
@@ -51,6 +54,7 @@ class Features {
|
|
|
51
54
|
this._hasMobileDoubleCall = this._hasFeatures(scopes, 'mobile_double_call');
|
|
52
55
|
this._hasMobileGsm = this._hasFeatures(scopes, 'mobile_gsm');
|
|
53
56
|
this._hasMeeting = this._hasFeatures(scopes, 'meeting');
|
|
57
|
+
this._hasCallerID = this._hasFeatures(scopes, 'caller_id');
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
hasChat() {
|
|
@@ -81,6 +85,10 @@ class Features {
|
|
|
81
85
|
return this._hasMeeting;
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
hasCallerID() {
|
|
89
|
+
return this._hasCallerID;
|
|
90
|
+
}
|
|
91
|
+
|
|
84
92
|
_hasFeatures(scopes: Record<string, any>, featureName: string) {
|
|
85
93
|
const scopeName = getScopeName(featureName);
|
|
86
94
|
|
package/src/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ export { default as Room } from './domain/Room';
|
|
|
24
24
|
export { default as CallSession } from './domain/CallSession';
|
|
25
25
|
export { default as IndirectTransfer } from './domain/IndirectTransfer';
|
|
26
26
|
export { default as SwitchboardCall } from './domain/SwitchboardCall';
|
|
27
|
+
export { default as CallerID } from './domain/CallerID';
|
|
27
28
|
export { default as WebRTCPhone } from './domain/Phone/WebRTCPhone';
|
|
28
29
|
export { default as CTIPhone } from './domain/Phone/CTIPhone';
|
|
29
30
|
export { default as Meeting, MeetingCreateArguments, MeetingUpdateArguments } from './domain/Meeting';
|
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AsYouType, parsePhoneNumber as libParsePhoneNumber, CountryCode } from 'libphonenumber-js';
|
|
2
2
|
|
|
3
|
-
const PhoneNumberUtil = LibPhoneNumber.PhoneNumberUtil.getInstance();
|
|
4
|
-
const {
|
|
5
|
-
PhoneNumberFormat,
|
|
6
|
-
AsYouTypeFormatter,
|
|
7
|
-
} = LibPhoneNumber;
|
|
8
3
|
// eslint-disable-next-line
|
|
9
4
|
const EXTRA_CHAR_REGEXP = /[^+*\d]/g;
|
|
5
|
+
const DEFAULT_GUESSING_COUNTRIES: CountryCode[] = ['US', 'FR', 'GB', 'AU'];
|
|
10
6
|
|
|
11
7
|
const shouldBeFormatted = (number: string | null | undefined) => {
|
|
12
8
|
if (!number || number.length <= 5) {
|
|
@@ -24,7 +20,23 @@ const isSameCountry = (country1: string, country2: string) => {
|
|
|
24
20
|
return country1 === country2;
|
|
25
21
|
};
|
|
26
22
|
|
|
27
|
-
const
|
|
23
|
+
const guessParsePhoneNumber = (number: string, defaultCountry?: CountryCode, guessingCountries: CountryCode[] = DEFAULT_GUESSING_COUNTRIES) => {
|
|
24
|
+
const mergedCountries = [...new Set([defaultCountry, ...guessingCountries])].filter(Boolean) as CountryCode[];
|
|
25
|
+
|
|
26
|
+
let parsedNumber;
|
|
27
|
+
for (let i = 0; i < mergedCountries.length; i++) {
|
|
28
|
+
const country = mergedCountries[i];
|
|
29
|
+
|
|
30
|
+
parsedNumber = libParsePhoneNumber(number, country);
|
|
31
|
+
if (parsedNumber.isValid()) {
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return parsedNumber;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getDisplayableNumber = (rawNumber: string, country: CountryCode, asYouType = false, guessingCountries: CountryCode[] | undefined = DEFAULT_GUESSING_COUNTRIES): string => {
|
|
28
40
|
if (!rawNumber) {
|
|
29
41
|
return rawNumber;
|
|
30
42
|
}
|
|
@@ -38,18 +50,16 @@ const getDisplayableNumber = (rawNumber: string, country: string, asYouType = fa
|
|
|
38
50
|
let displayValue = '';
|
|
39
51
|
|
|
40
52
|
if (asYouType) {
|
|
41
|
-
|
|
42
|
-
number.split('').forEach(char => {
|
|
43
|
-
displayValue = formatter.inputDigit(char);
|
|
44
|
-
});
|
|
53
|
+
displayValue = new AsYouType(country).input(number);
|
|
45
54
|
} else {
|
|
46
55
|
try {
|
|
47
|
-
const parsedNumber =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const parsedNumber = guessParsePhoneNumber(number, country, guessingCountries);
|
|
57
|
+
if (parsedNumber?.isValid()) {
|
|
58
|
+
displayValue = isSameCountry(String(parsedNumber.country), country) ? parsedNumber.formatNational() : parsedNumber.formatInternational();
|
|
59
|
+
} else {
|
|
60
|
+
displayValue = rawNumber;
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
53
63
|
displayValue = rawNumber;
|
|
54
64
|
}
|
|
55
65
|
}
|
|
@@ -59,16 +69,13 @@ const getDisplayableNumber = (rawNumber: string, country: string, asYouType = fa
|
|
|
59
69
|
|
|
60
70
|
const parsePhoneNumber = (phoneNumber: string): string => phoneNumber.replace(EXTRA_CHAR_REGEXP, '');
|
|
61
71
|
|
|
62
|
-
const getCallableNumber = (number: string, country?:
|
|
72
|
+
const getCallableNumber = (number: string, country?: CountryCode): string => {
|
|
63
73
|
try {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return parsePhoneNumber(number);
|
|
74
|
+
const callableNumber = country ? getDisplayableNumber(number, country) : number;
|
|
75
|
+
return parsePhoneNumber(callableNumber);
|
|
69
76
|
} catch (_) {
|
|
70
77
|
return number;
|
|
71
78
|
}
|
|
72
79
|
};
|
|
73
80
|
|
|
74
|
-
export {
|
|
81
|
+
export { parsePhoneNumber, getDisplayableNumber, guessParsePhoneNumber, getCallableNumber, type CountryCode };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDisplayableNumber, getCallableNumber } from '../PhoneNumberUtil';
|
|
1
|
+
import { getDisplayableNumber, getCallableNumber, guessParsePhoneNumber } from '../PhoneNumberUtil';
|
|
2
2
|
|
|
3
3
|
describe('Formatting phone numbers', () => {
|
|
4
4
|
it('should not format all phone numbers', () => {
|
|
@@ -8,30 +8,34 @@ describe('Formatting phone numbers', () => {
|
|
|
8
8
|
expect(getDisplayableNumber('#23445433', 'DE')).toBe('#23445433');
|
|
9
9
|
expect(getDisplayableNumber('0080510', 'FR')).toBe('0080510');
|
|
10
10
|
});
|
|
11
|
+
|
|
11
12
|
it('should format real phone numbers', () => {
|
|
12
13
|
expect(getDisplayableNumber('+33675456545', 'FR')).toBe('06 75 45 65 45');
|
|
13
14
|
expect(getDisplayableNumber('0675456545', 'FR')).toBe('06 75 45 65 45');
|
|
14
15
|
expect(getDisplayableNumber('+33675456545', 'US')).toBe('+33 6 75 45 65 45');
|
|
15
|
-
expect(getDisplayableNumber('0675456545', 'US')).toBe('+
|
|
16
|
+
expect(getDisplayableNumber('0675456545', 'US')).toBe('+33 6 75 45 65 45');
|
|
16
17
|
expect(getDisplayableNumber('4188884356', 'US')).toBe('(418) 888-4356');
|
|
17
18
|
});
|
|
19
|
+
|
|
18
20
|
it('should format real phone numbers when typing', () => {
|
|
19
21
|
expect(getDisplayableNumber('+3367545', 'FR', true)).toBe('+33 6 75 45');
|
|
20
22
|
expect(getDisplayableNumber('067545', 'FR', true)).toBe('06 75 45');
|
|
21
23
|
expect(getDisplayableNumber('+3367545', 'US', true)).toBe('+33 6 75 45');
|
|
22
24
|
expect(getDisplayableNumber('067545', 'US', true)).toBe('067545');
|
|
23
|
-
expect(getDisplayableNumber('418808', 'US', true)).toBe('418
|
|
25
|
+
expect(getDisplayableNumber('418808', 'US', true)).toBe('(418) 808');
|
|
24
26
|
});
|
|
27
|
+
|
|
25
28
|
it('should use the international number if the country number is different from the given country', () => {
|
|
26
|
-
expect(getDisplayableNumber('00201005803648', 'FR')).toBe('+20
|
|
27
|
-
expect(getDisplayableNumber('+14188004554', 'FR')).toBe('+1 418
|
|
28
|
-
expect(getDisplayableNumber('00201005803648', 'EG')).toBe('
|
|
29
|
+
expect(getDisplayableNumber('00201005803648', 'FR')).toBe('+20 10 05803648');
|
|
30
|
+
expect(getDisplayableNumber('+14188004554', 'FR')).toBe('+1 418 800 4554');
|
|
31
|
+
expect(getDisplayableNumber('00201005803648', 'EG')).toBe('010 05803648');
|
|
29
32
|
expect(getDisplayableNumber('0634543450', 'FR')).toBe('06 34 54 34 50');
|
|
30
33
|
expect(getDisplayableNumber('4188034302', 'US')).toBe('(418) 803-4302');
|
|
31
34
|
expect(getDisplayableNumber('8775863230', 'CA')).toBe('(877) 586-3230');
|
|
32
35
|
expect(getDisplayableNumber('8775863230', 'US')).toBe('(877) 586-3230');
|
|
33
36
|
});
|
|
34
37
|
});
|
|
38
|
+
|
|
35
39
|
describe('getCallableNumber', () => {
|
|
36
40
|
it('works with a country', () => {
|
|
37
41
|
expect(getCallableNumber('+33 6 75 45 12 34', 'FR')).toBe('0675451234');
|
|
@@ -43,6 +47,7 @@ describe('getCallableNumber', () => {
|
|
|
43
47
|
expect(getCallableNumber('*10', 'US')).toBe('*10');
|
|
44
48
|
expect(getCallableNumber('9000', 'US')).toBe('9000');
|
|
45
49
|
});
|
|
50
|
+
|
|
46
51
|
it('works without a country', () => {
|
|
47
52
|
expect(getCallableNumber('06 75 45')).toBe('067545');
|
|
48
53
|
expect(getCallableNumber('067-545')).toBe('067545');
|
|
@@ -52,3 +57,23 @@ describe('getCallableNumber', () => {
|
|
|
52
57
|
expect(getCallableNumber('9000')).toBe('9000');
|
|
53
58
|
});
|
|
54
59
|
});
|
|
60
|
+
|
|
61
|
+
describe('guessParsePhoneNumber', () => {
|
|
62
|
+
it('should guess with default countries', () => {
|
|
63
|
+
const parsedNumber = guessParsePhoneNumber('0675456545');
|
|
64
|
+
expect(parsedNumber?.country).toBe('FR');
|
|
65
|
+
expect(parsedNumber?.isValid()).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should guess with specified countries', () => {
|
|
69
|
+
const parsedNumber = guessParsePhoneNumber('752097514', undefined, ['JP']);
|
|
70
|
+
expect(parsedNumber?.country).toBe('JP');
|
|
71
|
+
expect(parsedNumber?.isValid()).toBe(true);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should used use defaultCountry has guesser', () => {
|
|
75
|
+
const parsedNumber = guessParsePhoneNumber('752097514', 'JP', []);
|
|
76
|
+
expect(parsedNumber?.country).toBe('JP');
|
|
77
|
+
expect(parsedNumber?.isValid()).toBe(true);
|
|
78
|
+
});
|
|
79
|
+
});
|