Skip to content

Commit efe6e10

Browse files
authored
feat: meeting schedule api and dialer/meeting status events (#356)
* feat: add events of dialer and meeting status, meeting schedule api * add docs * fix dialer status issue
1 parent c764d0d commit efe6e10

File tree

8 files changed

+252
-9
lines changed

8 files changed

+252
-9
lines changed

docs/control-widget.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,58 @@ Remove:
217217
```
218218
RCAdapter.dispose();
219219
```
220+
221+
## Navigate To
222+
223+
Navigate to path:
224+
225+
```js
226+
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
227+
type: 'rc-adapter-navigate-to',
228+
path: '/messages', // '/meeting', '/dialer', '//history', '/settings'
229+
}, '*');
230+
```
231+
232+
## Schedule a meeting
233+
234+
```js
235+
// meeting info
236+
const meetingBody = {
237+
topic: "Embbnux Ji's Meeting",
238+
meetingType: "Scheduled",
239+
password: "",
240+
schedule: {
241+
startTime: 1583312400368,
242+
durationInMinutes: 60,
243+
timeZone: {
244+
id: "1"
245+
}
246+
},
247+
allowJoinBeforeHost: false,
248+
startHostVideo: false,
249+
startParticipantsVideo: false,
250+
audioOptions: [
251+
"Phone",
252+
"ComputerAudio"
253+
]
254+
};
255+
256+
// send a request to schedule meeting
257+
const requestId = Date.now().toString();
258+
document.querySelector("#rc-widget-adapter-frame").contentWindow.postMessage({
259+
type: 'rc-adapter-message-request',
260+
requestId: requestId,
261+
path: '/schedule-meeting',
262+
body: meetingBody,
263+
}, '*');
264+
265+
// listen response
266+
window.addEventListener('message', function (e) {
267+
var data = e.data;
268+
if (data && data.type === 'rc-adapter-message-response') {
269+
if (data.responseId === requestId) {
270+
console.log(data.response);
271+
}
272+
}
273+
});
274+
```

docs/widget-event.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,45 @@ window.addEventListener('message', (e) => {
201201
}
202202
});
203203
```
204+
205+
## Dialer status event
206+
207+
Before we use [GoToDial](control-widget.md#go-to-dial-and-start-a-call) API, we need to check dialer status.
208+
209+
Get dialer status:
210+
211+
```js
212+
window.addEventListener('message', (e) => {
213+
const data = e.data;
214+
if (data) {
215+
switch (data.type) {
216+
case 'rc-dialer-status-notify':
217+
// get dialer status from widget
218+
console.log('rc-dialer-status-notify:', data.ready);
219+
break;
220+
default:
221+
break;
222+
}
223+
}
224+
});
225+
```
226+
227+
## Meeting status event
228+
229+
Get meeting status and permission:
230+
231+
```js
232+
window.addEventListener('message', (e) => {
233+
const data = e.data;
234+
if (data) {
235+
switch (data.type) {
236+
case 'rc-meeting-status-notify':
237+
// get meeting status and permission from widget
238+
console.log('rc-meeting-status-notify:', data.ready, data.permission);
239+
break;
240+
default:
241+
break;
242+
}
243+
}
244+
});
245+
```

src/lib/Adapter/index.js

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import url from 'url';
44

55
import parseUri from '../parseUri';
66
import messageTypes from './messageTypes';
7+
import requestWithPostMessage from '../requestWithPostMessage';
78

89
import styles from './styles.scss';
910
import Notification from '../notification';
@@ -151,10 +152,10 @@ class Adapter extends AdapterCore {
151152
console.log('rc-login-status-notify:', data.loggedIn, data.loginNumber);
152153
break;
153154
case 'rc-calling-settings-notify':
154-
console.log('rc-calling-settings-notify:', data);
155+
console.log('rc-calling-settings-notify:', data.callWith, data.callingMode);
155156
break;
156157
case 'rc-region-settings-notify':
157-
console.log('rc-region-settings-notify:', data);
158+
console.log('rc-region-settings-notify:', data.countryCode, data.areaCode);
158159
break;
159160
case 'rc-active-call-notify':
160161
console.log('rc-active-call-notify:', data.call);
@@ -175,6 +176,12 @@ class Adapter extends AdapterCore {
175176
case 'rc-callLogger-auto-log-notify':
176177
console.log('rc-callLogger-auto-log-notify:', data.autoLog);
177178
break;
179+
case 'rc-dialer-status-notify':
180+
console.log('rc-dialer-status-notify:', data.ready);
181+
break;
182+
case 'rc-meeting-status-notify':
183+
console.log('rc-meeting-status-notify:', data.ready, data.permission);
184+
break;
178185
default:
179186
super._onMessage(data);
180187
break;
@@ -322,6 +329,16 @@ class Adapter extends AdapterCore {
322329
}
323330
}
324331

332+
_requestWithPostMessage(path, body) {
333+
return requestWithPostMessage(
334+
path,
335+
body,
336+
5000,
337+
this._contentFrameEl.contentWindow,
338+
'rc-adapter-message'
339+
);
340+
}
341+
325342
setRinging(ringing) {
326343
this._ringing = !!ringing;
327344
this._renderMainClass();
@@ -382,6 +399,17 @@ class Adapter extends AdapterCore {
382399
});
383400
}
384401

402+
navigateTo(path) {
403+
this._postMessage({
404+
type: 'rc-adapter-navigate-to',
405+
path,
406+
});
407+
}
408+
409+
scheduleMeeting(meetingInfo) {
410+
return this._requestWithPostMessage('/schedule-meeting', meetingInfo);
411+
}
412+
385413
_updateWidgetCurrentPath(path) {
386414
this._widgetCurrentPath = path;
387415
this._updateCallBarStatus();

src/lib/requestWithPostMessage.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
import uuid from 'uuid';
22

3-
export default function requestWithPostMessage(path, body, timeout = 3000) {
3+
export default function requestWithPostMessage(path, body, timeout = 3000, target = window.parent, prefix = 'rc-post-message') {
44
return new Promise((resolve, reject) => {
55
const id = uuid.v4();
66
let responseFunc;
77
const catchTimeout = setTimeout(() => {
88
window.removeEventListener('message', responseFunc);
9-
reject('Time out');
9+
reject(Error('Time out'));
1010
}, timeout);
1111
responseFunc = (e) => {
1212
const data = e.data;
1313
if (
1414
data &&
15-
data.type === 'rc-post-message-response' &&
15+
data.type === `${prefix}-response` &&
1616
data.responseId === id
1717
) {
1818
clearTimeout(catchTimeout);
1919
window.removeEventListener('message', responseFunc);
2020
resolve(data.response);
2121
}
2222
};
23-
window.parent.postMessage({
24-
type: 'rc-post-message-request',
23+
target.postMessage({
24+
type: `${prefix}-request`,
2525
requestId: id,
2626
path,
2727
body,

src/modules/Adapter/index.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import debounce from 'ringcentral-integration/lib/debounce';
1212

1313
import AdapterModuleCore from 'ringcentral-widgets/lib/AdapterModuleCore';
1414

15+
import formatMeetingInfo from '../../lib/formatMeetingInfo';
1516
import messageTypes from '../../lib/Adapter/messageTypes';
1617
import actionTypes from './actionTypes';
1718
import getReducer from './getReducer';
@@ -25,6 +26,7 @@ const CALL_NOTIFY_DELAY = 1500;
2526
'ExtensionInfo',
2627
'AccountInfo',
2728
'RouterInteraction',
29+
'RolesAndPermissions',
2830
'Presence',
2931
'ComposeText',
3032
'Call',
@@ -38,6 +40,8 @@ const CALL_NOTIFY_DELAY = 1500;
3840
'MessageStore',
3941
'TabManager',
4042
'CallLogger',
43+
'Meeting',
44+
'Brand',
4145
{ dep: 'AdapterOptions', optional: true }
4246
]
4347
})
@@ -61,6 +65,9 @@ export default class Adapter extends AdapterModuleCore {
6165
disableInactiveTabCallEvent,
6266
tabManager,
6367
callLogger,
68+
meeting,
69+
brand,
70+
rolesAndPermissions,
6471
...options
6572
}) {
6673
super({
@@ -87,6 +94,9 @@ export default class Adapter extends AdapterModuleCore {
8794
this._callLogger = callLogger;
8895
this._extensionInfo = extensionInfo;
8996
this._accountInfo = accountInfo;
97+
this._meeting = meeting;
98+
this._brand = brand;
99+
this._rolesAndPermissions = rolesAndPermissions;
90100

91101
this._reducer = getReducer(this.actionTypes);
92102
this._callSessions = new Map();
@@ -99,6 +109,8 @@ export default class Adapter extends AdapterModuleCore {
99109
this._lastActiveCallLogMap = {};
100110
this._callWith = null;
101111
this._callLoggerAutoLogEnabled = null;
112+
this._dialerDisabled = null;
113+
this._meetingReady = null;
102114

103115
this._messageStore.onNewInboundMessage((message) => {
104116
this._postMessage({
@@ -176,6 +188,8 @@ export default class Adapter extends AdapterModuleCore {
176188
this._checkRouteChanged();
177189
this._checkCallingSettingsChanged();
178190
this._checkAutoCallLoggerChanged();
191+
this._checkDialUIStatusChanged();
192+
this._checkMeetingStatusChanged();
179193
}
180194

181195
_onMessage(event) {
@@ -205,13 +219,49 @@ export default class Adapter extends AdapterModuleCore {
205219
if (this._callingSettings.ready) {
206220
this._updateCallingSettings(data);
207221
}
222+
break;
223+
case 'rc-adapter-message-request': {
224+
this._handleRCAdapterMessageRequest(data);
225+
break;
226+
}
227+
case 'rc-adapter-navigate-to': {
228+
if (data.path && data.path.indexOf('/') === 0) {
229+
this._router.push(data.path);
230+
}
231+
break;
232+
}
208233
default:
209234
super._onMessage(data);
210235
break;
211236
}
212237
}
213238
}
214239

240+
async _handleRCAdapterMessageRequest(data) {
241+
if (!data.path) {
242+
return;
243+
}
244+
switch (data.path) {
245+
case '/schedule-meeting': {
246+
if (this._meeting.ready && this._rolesAndPermissions.organizeMeetingEnabled) {
247+
const res = await this._scheduleMeeting(data.body);
248+
this._postRCAdapterMessageResponse({
249+
responseId: data.requestId,
250+
response: res,
251+
});
252+
}
253+
break;
254+
}
255+
default: {
256+
this._postRCAdapterMessageResponse({
257+
responseId: data.requestId,
258+
response: { data: 'no matched path' }
259+
});
260+
break;
261+
}
262+
}
263+
}
264+
215265
_pushAdapterState() {
216266
this._postMessage({
217267
type: this._messageTypes.pushAdapterState,
@@ -417,6 +467,32 @@ export default class Adapter extends AdapterModuleCore {
417467
this._postMessage(message);
418468
}
419469

470+
_checkDialUIStatusChanged() {
471+
if (this._dialerDisabled === this._dialerUI.isCallButtonDisabled) {
472+
return;
473+
}
474+
this._dialerDisabled = this._dialerUI.isCallButtonDisabled;
475+
this._postMessage({
476+
type: 'rc-dialer-status-notify',
477+
ready: !this._dialerUI.showSpinner && !this._dialerUI.isCallButtonDisabled,
478+
});
479+
}
480+
481+
_checkMeetingStatusChanged() {
482+
if (this._meetingReady === this._meeting.ready) {
483+
return;
484+
}
485+
this._meetingReady = this._meeting.ready;
486+
this._postMessage({
487+
type: 'rc-meeting-status-notify',
488+
ready: this._meeting.ready,
489+
permission: !!(
490+
this._rolesAndPermissions.ready &&
491+
this._rolesAndPermissions.organizeMeetingEnabled
492+
),
493+
});
494+
}
495+
420496
_insertExtendStyle() {
421497
if (!this._stylesUri) {
422498
return;
@@ -618,13 +694,34 @@ export default class Adapter extends AdapterModuleCore {
618694
}
619695
}
620696

697+
async _scheduleMeeting(data) {
698+
const resp = await phone.meeting.schedule(data);
699+
if (!resp) {
700+
return {
701+
error: 'schedule failed'
702+
};
703+
}
704+
const formatedMeetingInfo = formatMeetingInfo(resp, this._brand, this._locale.currentLocale);
705+
return {
706+
meeting: formatedMeetingInfo,
707+
};
708+
}
709+
621710
// eslint-disable-next-line
622711
_postMessage(data) {
623712
if (window && window.parent) {
624713
window.parent.postMessage(data, '*');
625714
}
626715
}
627716

717+
_postRCAdapterMessageResponse({ responseId, response }) {
718+
this._postMessage({
719+
type: 'rc-adapter-message-response',
720+
responseId,
721+
response,
722+
});
723+
}
724+
628725
get ready() {
629726
return this.state.status === moduleStatuses.ready;
630727
}

0 commit comments

Comments
 (0)