Skip to content

Commit c316944

Browse files
authored
Improve getTextDescriptionForCallevent & introduce frontend error for phonenumber conflict (#128)
* work on improving getTextDescription, plus introduce some tests for it. * working on callEvent formatting * working on callEvent description formatting * fix calculation of call duration format string, which calculated wrong values for the seconds of a call duration. * fix description string for busy & not_found calls * add test cases for not_found callevent * minor renaming of test cases * implement getTextDescriptionForCallevent for english language * adding IntegrationErrorType.CONTACT_ERROR_PHONENUMBER_EXISTS * 1.0.10
1 parent 9561dcd commit c316944

File tree

5 files changed

+267
-24
lines changed

5 files changed

+267
-24
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sipgate/integration-bridge",
3-
"version": "1.0.9",
3+
"version": "1.0.10",
44
"description": "sipgate Integration Bridge Framework",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/models/integration-error.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum IntegrationErrorType {
1616
CONTACT_CREATE_ERROR_EMAIL_CONFLICT = 'contact/create-error/email-conflict',
1717
CONTACT_ERROR_TOO_MANY_NUMBERS = 'contact/error/too-many-numbers',
1818
CONTACT_ERROR_INVALID_PHONE_TYPE = 'contact/error/invalid-phone-type',
19+
CONTACT_ERROR_PHONENUMBER_EXISTS = 'contact/error/phonenumber-exists',
1920
}
2021

2122
export const DELEGATE_TO_FRONTEND_CODE = 452;

src/util/callEventHelper.test.ts

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import {
2+
CallDirection,
3+
CallEvent,
4+
CallParticipantType,
5+
CallState,
6+
} from '../models';
7+
import { getTextDescriptionForCallevent } from './callEventHelper';
8+
9+
const generateBaseCallEvent = (): CallEvent => ({
10+
id: 'callEventId123',
11+
startTime: 1705832625000,
12+
endTime: 1705833276000,
13+
direction: CallDirection.IN,
14+
participants: [
15+
{
16+
type: CallParticipantType.LOCAL,
17+
phoneNumber: '4921177722233',
18+
},
19+
{
20+
type: CallParticipantType.REMOTE,
21+
phoneNumber: '4922199911122',
22+
},
23+
],
24+
note: 'testnote01',
25+
state: CallState.CONNECTED,
26+
});
27+
28+
describe('callEventHelper', () => {
29+
describe('getTextDescriptionForCallevent for german locale', () => {
30+
it('should generate sane description for incoming, connected callEvent', () => {
31+
const callEvent = generateBaseCallEvent();
32+
33+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
34+
'Angenommener eingehender Anruf von 4922199911122 auf 4921177722233 am 21.1.2024, 11:23:45 Uhr, Dauer: 10:51 Minuten.',
35+
);
36+
});
37+
38+
it('should generate sane description for outgoing, connected callEvent', () => {
39+
const callEvent = generateBaseCallEvent();
40+
callEvent.direction = CallDirection.OUT;
41+
42+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
43+
'Angenommener ausgehender Anruf von 4921177722233 auf 4922199911122 am 21.1.2024, 11:23:45 Uhr, Dauer: 10:51 Minuten.',
44+
);
45+
});
46+
47+
it('should generate sane description for incoming, missed callEvent', () => {
48+
const callEvent = generateBaseCallEvent();
49+
callEvent.state = CallState.MISSED;
50+
51+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
52+
'Nicht angenommener eingehender Anruf von 4922199911122 auf 4921177722233 am 21.1.2024, 11:23:45 Uhr.',
53+
);
54+
});
55+
56+
it('should generate sane description for outgoing, missed callEvent', () => {
57+
const callEvent = generateBaseCallEvent();
58+
callEvent.direction = CallDirection.OUT;
59+
callEvent.state = CallState.MISSED;
60+
61+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
62+
'Nicht angenommener ausgehender Anruf von 4921177722233 auf 4922199911122 am 21.1.2024, 11:23:45 Uhr.',
63+
);
64+
});
65+
66+
it('should generate sane description for incoming, busy callEvent', () => {
67+
const callEvent = generateBaseCallEvent();
68+
callEvent.state = CallState.BUSY;
69+
70+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
71+
'Nicht angenommener eingehender Anruf von 4922199911122 auf 4921177722233 am 21.1.2024, 11:23:45 Uhr.',
72+
);
73+
});
74+
75+
it('should generate sane description for outgoing, busy callEvent', () => {
76+
const callEvent = generateBaseCallEvent();
77+
callEvent.direction = CallDirection.OUT;
78+
callEvent.state = CallState.BUSY;
79+
80+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
81+
'Nicht angenommener ausgehender Anruf von 4921177722233 auf 4922199911122 am 21.1.2024, 11:23:45 Uhr.',
82+
);
83+
});
84+
85+
it('should generate sane description for incoming, not_found callEvent', () => {
86+
const callEvent = generateBaseCallEvent();
87+
callEvent.state = CallState.NOT_FOUND;
88+
89+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
90+
'Nicht angenommener eingehender Anruf von 4922199911122 auf 4921177722233 am 21.1.2024, 11:23:45 Uhr.',
91+
);
92+
});
93+
94+
it('should generate sane description for outgoing, not_found callEvent', () => {
95+
const callEvent = generateBaseCallEvent();
96+
callEvent.direction = CallDirection.OUT;
97+
callEvent.state = CallState.NOT_FOUND;
98+
99+
expect(getTextDescriptionForCallevent(callEvent)).toEqual(
100+
'Nicht angenommener ausgehender Anruf von 4921177722233 auf 4922199911122 am 21.1.2024, 11:23:45 Uhr.',
101+
);
102+
});
103+
});
104+
105+
describe('getTextDescriptionForCallevent for english locale', () => {
106+
it('should generate sane description for incoming, connected callEvent', () => {
107+
const callEvent = generateBaseCallEvent();
108+
109+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
110+
'Answered incoming call from 4922199911122 to 4921177722233 on 1/21/2024, 11:23:45 AM, duration: 10:51 minutes.',
111+
);
112+
});
113+
114+
it('should generate sane description for outgoing, connected callEvent', () => {
115+
const callEvent = generateBaseCallEvent();
116+
callEvent.direction = CallDirection.OUT;
117+
118+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
119+
'Answered outgoing call from 4921177722233 to 4922199911122 on 1/21/2024, 11:23:45 AM, duration: 10:51 minutes.',
120+
);
121+
});
122+
123+
it('should generate sane description for incoming, missed callEvent', () => {
124+
const callEvent = generateBaseCallEvent();
125+
callEvent.state = CallState.MISSED;
126+
127+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
128+
'Unanswered incoming call from 4922199911122 to 4921177722233 on 1/21/2024, 11:23:45 AM.',
129+
);
130+
});
131+
132+
it('should generate sane description for outgoing, missed callEvent', () => {
133+
const callEvent = generateBaseCallEvent();
134+
callEvent.direction = CallDirection.OUT;
135+
callEvent.state = CallState.MISSED;
136+
137+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
138+
'Unanswered outgoing call from 4921177722233 to 4922199911122 on 1/21/2024, 11:23:45 AM.',
139+
);
140+
});
141+
142+
it('should generate sane description for incoming, busy callEvent', () => {
143+
const callEvent = generateBaseCallEvent();
144+
callEvent.state = CallState.BUSY;
145+
146+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
147+
'Unanswered incoming call from 4922199911122 to 4921177722233 on 1/21/2024, 11:23:45 AM.',
148+
);
149+
});
150+
151+
it('should generate sane description for outgoing, busy callEvent', () => {
152+
const callEvent = generateBaseCallEvent();
153+
callEvent.direction = CallDirection.OUT;
154+
callEvent.state = CallState.BUSY;
155+
156+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
157+
'Unanswered outgoing call from 4921177722233 to 4922199911122 on 1/21/2024, 11:23:45 AM.',
158+
);
159+
});
160+
161+
it('should generate sane description for incoming, not_found callEvent', () => {
162+
const callEvent = generateBaseCallEvent();
163+
callEvent.state = CallState.NOT_FOUND;
164+
165+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
166+
'Unanswered incoming call from 4922199911122 to 4921177722233 on 1/21/2024, 11:23:45 AM.',
167+
);
168+
});
169+
170+
it('should generate sane description for outgoing, not_found callEvent', () => {
171+
const callEvent = generateBaseCallEvent();
172+
callEvent.direction = CallDirection.OUT;
173+
callEvent.state = CallState.NOT_FOUND;
174+
175+
expect(getTextDescriptionForCallevent(callEvent, 'en-US')).toEqual(
176+
'Unanswered outgoing call from 4921177722233 to 4922199911122 on 1/21/2024, 11:23:45 AM.',
177+
);
178+
});
179+
});
180+
});

src/util/callEventHelper.ts

Lines changed: 83 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { CallEvent, CallParticipantType, CallDirection } from '../models';
1+
import { startsWith } from 'lodash';
2+
import {
3+
CallEvent,
4+
CallParticipantType,
5+
CallDirection,
6+
CallState,
7+
} from '../models';
28

39
export interface CallMembers {
410
from: string | undefined;
@@ -24,35 +30,91 @@ export const getCallMembers = (event: CallEvent): CallMembers => {
2430

2531
return { from, to };
2632
};
27-
function formatDuration(durationInMilliSeconds: number): string {
28-
const minutes = Math.floor(durationInMilliSeconds / (60 * 1000));
29-
const seconds = Math.floor((durationInMilliSeconds - minutes * 60) / 1000)
33+
34+
const formatDuration = (
35+
durationInMilliSeconds: number,
36+
locale: string,
37+
): string => {
38+
const minutes = Math.floor(durationInMilliSeconds / 1000 / 60);
39+
const seconds = (durationInMilliSeconds / 1000) % 60;
40+
const unit = startsWith(locale, 'de') ? 'Minuten' : 'minutes';
41+
42+
return `${minutes}:${seconds
3043
.toString()
3144
.padStart(2, '0')
32-
.substring(0, 2);
33-
return `${minutes}:${seconds} min`;
34-
}
45+
.substring(0, 2)} ${unit}`;
46+
};
3547

36-
export const getTextDescriptionForCallevent = (
48+
const getGermanTextDescriptionForCallEvent = (
3749
callEvent: CallEvent,
50+
locale: string,
3851
): string => {
3952
const date = new Date(callEvent.startTime);
40-
const duration = callEvent.endTime
41-
? formatDuration(callEvent.endTime - callEvent.startTime)
42-
: 0;
53+
54+
const duration = formatDuration(
55+
callEvent.endTime ? callEvent.endTime - callEvent.startTime : 0,
56+
locale,
57+
);
58+
4359
const directionInfo =
4460
callEvent.direction === CallDirection.IN ? 'eingehender' : 'ausgehender';
61+
4562
const { from, to } = getCallMembers(callEvent);
46-
const fromDescription = from ? ` von ${from}` : '';
47-
const toDescription = to ? ` auf ${to}` : '';
48-
const callDescription = `${fromDescription}${toDescription}`;
63+
const fromDescription = from ? `von ${from}` : '';
64+
const toDescription = to ? `auf ${to}` : '';
65+
66+
const callDescription = `${fromDescription}${
67+
fromDescription && toDescription ? ' ' : ''
68+
}${toDescription}`;
69+
4970
const callState =
50-
callEvent.state === 'MISSED' ? 'Nicht angenommener ' : 'Angenommener';
71+
callEvent.state === CallState.CONNECTED
72+
? 'Angenommener'
73+
: 'Nicht angenommener';
5174
const durationInfo =
52-
callEvent.state === 'MISSED' ? '' : ` ,Dauer: ${duration}`;
53-
const result = `${callState} ${directionInfo} Anruf ${callDescription} am ${date.toLocaleString(
54-
'de',
55-
{ timeZone: 'Europe/Berlin' },
56-
)} ${durationInfo}`;
57-
return result;
75+
callEvent.state === CallState.CONNECTED ? `, Dauer: ${duration}` : '';
76+
const callDate = date.toLocaleString('de', { timeZone: 'Europe/Berlin' });
77+
const description = `${callState} ${directionInfo} Anruf ${callDescription} am ${callDate} Uhr${durationInfo}.`;
78+
79+
return description;
80+
};
81+
82+
const getEnglishTextDescriptionForCallEvent = (
83+
callEvent: CallEvent,
84+
locale: string,
85+
): string => {
86+
const date = new Date(callEvent.startTime);
87+
const duration = formatDuration(
88+
callEvent.endTime ? callEvent.endTime - callEvent.startTime : 0,
89+
locale,
90+
);
91+
92+
const directionInfo =
93+
callEvent.direction === CallDirection.IN ? 'incoming' : 'outgoing';
94+
95+
const { from, to } = getCallMembers(callEvent);
96+
const fromDescription = from ? `from ${from}` : '';
97+
const toDescription = to ? `to ${to}` : '';
98+
99+
const callDescription = `${fromDescription}${
100+
fromDescription && toDescription ? ' ' : ''
101+
}${toDescription}`;
102+
103+
const callState =
104+
callEvent.state === CallState.CONNECTED ? 'Answered' : 'Unanswered';
105+
const durationInfo =
106+
callEvent.state === CallState.CONNECTED ? `, duration: ${duration}` : '';
107+
const callDate = date.toLocaleString('en', { timeZone: 'Europe/Berlin' });
108+
const description = `${callState} ${directionInfo} call ${callDescription} on ${callDate}${durationInfo}.`;
109+
110+
return description;
111+
};
112+
113+
export const getTextDescriptionForCallevent = (
114+
callEvent: CallEvent,
115+
locale: string = 'de-DE',
116+
): string => {
117+
return startsWith(locale, 'de')
118+
? getGermanTextDescriptionForCallEvent(callEvent, locale)
119+
: getEnglishTextDescriptionForCallEvent(callEvent, locale);
58120
};

0 commit comments

Comments
 (0)