Skip to content

Commit babac89

Browse files
authored
Merge pull request #268 from allchiang-msft/allchiang-msft/manage-rooms-panel
Add more Rooms functionality with new Manage Rooms panel
2 parents cc78bb9 + fc62406 commit babac89

File tree

5 files changed

+187
-52
lines changed

5 files changed

+187
-52
lines changed

Project/package-lock.json

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

Project/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
"version": "1.0.0",
44
"private": true,
55
"dependencies": {
6-
"@azure/communication-calling": "1.33.2-beta.1",
6+
"@azure/communication-calling": "1.34.1-beta.2",
77
"@azure/communication-calling-effects": "1.1.1-beta.1",
88
"@azure/communication-common": "^2.3.0",
99
"@azure/communication-identity": "^1.3.0",
1010
"@azure/communication-network-traversal": "^1.1.0-beta.1",
11-
"@azure/communication-rooms": "1.1.1",
11+
"@azure/communication-rooms": "1.2.0",
1212
"@azure/logger": "^1.0.3",
1313
"@azure/msal-browser": "^2.33.0",
1414
"@azure/msal-node": "^1.17.1",

Project/src/MakeCall/MakeCall.js

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { CallClient, LocalVideoStream, Features, CallAgentKind, VideoStreamRende
33
import { AzureCommunicationTokenCredential, createIdentifierFromRawId} from '@azure/communication-common';
44
import { PrimaryButton } from '@fluentui/react/lib/Button';
55
import { TextField } from '@fluentui/react/lib/TextField';
6-
import { MessageBar, MessageBarType } from '@fluentui/react';
6+
import { MessageBar, MessageBarType, Toggle } from '@fluentui/react';
77
import { Icon } from '@fluentui/react/lib/Icon';
88
import IncomingCallCard from './IncomingCallCard';
99
import CallCard from '../MakeCall/CallCard';
@@ -34,9 +34,13 @@ export default class MakeCall extends React.Component {
3434
this.meetingLink = null;
3535
this.meetingId = null;
3636
this.passcode = null;
37-
this.presenterUserId = null;
38-
this.attendeeUserId = null;
39-
this.consumerUserId = null;
37+
this.presenterUserIds = null;
38+
this.collaboratorUserIds = null;
39+
this.attendeeUserIds = null;
40+
this.consumerUserIds = null;
41+
this.patchRoomId = null;
42+
this.patchParticipantId = null;
43+
this.patchParticipantRole = null;
4044
this.threadId = null;
4145
this.messageId = null;
4246
this.organizerId = null;
@@ -62,7 +66,8 @@ export default class MakeCall extends React.Component {
6266
showPreCallDiagnostcisResults: false,
6367
showCustomContext: false,
6468
roomId: undefined,
65-
showCreateRoomPanel: false,
69+
roomPstnDialOutEnabled: true,
70+
showManageRoomsPanel: false,
6671
xHeadersCount: 1,
6772
xHeadersMaxCount: 5,
6873
isPreCallDiagnosticsCallInProgress: false,
@@ -374,14 +379,23 @@ export default class MakeCall extends React.Component {
374379

375380
createRoom = async () => {
376381
try {
377-
const roomId = await utils.createRoom(this.presenterUserId.value, this.attendeeUserId.value, this.consumerUserId.value);
382+
const roomId = await utils.createRoom(this.state.roomPstnDialOutEnabled, this.presenterUserIds.value, this.collaboratorUserIds.value, this.attendeeUserIds.value, this.consumerUserIds.value);
378383
console.log('Room id created: ', roomId);
379384
this.setState({ roomId });
380385
} catch (e) {
381386
console.error('Failed to create a room: ', e);
382387
}
383388
};
384389

390+
updateParticipant = async () => {
391+
try {
392+
await utils.updateParticipant(this.patchRoomId.value, this.patchParticipantId.value, this.patchParticipantRole.value);
393+
console.log('Participant updated successfully');
394+
} catch (e) {
395+
console.error('Failed to update participant ', e);
396+
}
397+
};
398+
385399
joinTeamsMeeting = async (withVideo, micMuted = false) => {
386400
try {
387401
const callOptions = await this.getCallOptions({video: withVideo, micMuted: micMuted});
@@ -1175,7 +1189,7 @@ this.callAgent.on('incomingCall', async (args) => {
11751189
disabled={this.state.call || !this.state.loggedIn}
11761190
label="Rooms id"
11771191
value={ this.state.roomId }
1178-
placeholder="<GUID>"
1192+
placeholder="<Room ID (starts with 9)>"
11791193
onChange={(e) => this.setState({ roomId: e.target.value })}/>
11801194
</div>
11811195
</div>
@@ -1193,44 +1207,83 @@ this.callAgent.on('incomingCall', async (args) => {
11931207
</PrimaryButton>
11941208
<PrimaryButton className="primary-button"
11951209
iconProps={{ iconName: 'Group', style: { verticalAlign: 'middle', fontSize: 'large' } }}
1196-
text="Create a room"
1197-
disabled={this.state.call || !this.state.loggedIn}
1198-
onClick={() => this.setState({ showCreateRoomPanel: !this.state.showCreateRoomPanel })}>
1210+
text="Manage Rooms"
1211+
onClick={() => this.setState({ showManageRoomsPanel: !this.state.showManageRoomsPanel })}>
11991212
</PrimaryButton>
12001213
</div>
12011214
{
1202-
this.state.showCreateRoomPanel &&
1215+
this.state.showManageRoomsPanel &&
12031216
<div className="mt-5">
1204-
<h2 className="mb-0">Create a Room</h2>
1217+
<h2 className="mb-0">Manage Rooms</h2>
1218+
<h3 className="mb-0">Create a Room</h3>
12051219
<div className="ms-Grid-row">
1220+
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
1221+
<Toggle className="mb-3 mt-0"
1222+
checked={this.state.roomPstnDialOutEnabled}
1223+
label="PSTN Dial Out Enabled"
1224+
onText="True"
1225+
offText="False"
1226+
onClick={() => {
1227+
console.log(this.state.roomPstnDialOutEnabled);
1228+
this.setState({roomPstnDialOutEnabled: !this.state.roomPstnDialOutEnabled})
1229+
}} />
1230+
</div>
12061231
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
12071232
<TextField className="mb-3 mt-0"
1208-
disabled={this.state.call || !this.state.loggedIn}
1209-
label="Presenter user id"
1233+
label="Presenter user ids (comma delimited)"
12101234
placeholder="8:acs:<ACS resource ID>_<GUID>"
1211-
componentRef={(val) => this.presenterUserId = val} />
1235+
componentRef={(val) => this.presenterUserIds = val} />
12121236
</div>
12131237
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
12141238
<TextField className="mb-3 mt-0"
1215-
disabled={this.state.call || !this.state.loggedIn}
1216-
label="Attendee user id"
1239+
label="Collaborator user ids (comma delimited)"
12171240
placeholder="8:acs:<ACS resource ID>_<GUID>"
1218-
componentRef={(val) => this.attendeeUserId = val} />
1241+
componentRef={(val) => this.collaboratorUserIds = val} />
12191242
</div>
12201243
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
12211244
<TextField className="mb-3 mt-0"
1222-
disabled={this.state.call || !this.state.loggedIn}
1223-
label="Consumer user id"
1245+
label="Attendee user ids (comma delimited)"
12241246
placeholder="8:acs:<ACS resource ID>_<GUID>"
1225-
componentRef={(val) => this.consumerUserId = val} />
1247+
componentRef={(val) => this.attendeeUserIds = val} />
12261248
</div>
1227-
</div>
1228-
<PrimaryButton className="primary-button"
1249+
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
1250+
<TextField className="mb-3 mt-0"
1251+
label="Consumer user ids (comma delimited)"
1252+
placeholder="8:acs:<ACS resource ID>_<GUID>"
1253+
componentRef={(val) => this.consumerUserIds = val} />
1254+
</div>
1255+
<PrimaryButton className="primary-button"
12291256
iconProps={{ iconName: 'Video', style: { verticalAlign: 'middle', fontSize: 'large' } }}
12301257
text="Create room"
1231-
disabled={this.state.call || !this.state.loggedIn}
12321258
onClick={() => this.createRoom()}>
1233-
</PrimaryButton>
1259+
</PrimaryButton>
1260+
</div>
1261+
<h3 className="mb-0">Update a Participant</h3>
1262+
<div className="ms-Grid-row">
1263+
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
1264+
<TextField className="mb-3 mt-0"
1265+
label="Room ID"
1266+
placeholder="Room ID (9xxxxxx)"
1267+
componentRef={(val) => this.patchRoomId = val} />
1268+
</div>
1269+
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
1270+
<TextField className="mb-3 mt-0"
1271+
label="Participant user ID"
1272+
placeholder="8:acs:<ACS resource ID>_<GUID>"
1273+
componentRef={(val) => this.patchParticipantId = val} />
1274+
</div>
1275+
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
1276+
<TextField className="mb-3 mt-0"
1277+
label="Role"
1278+
placeholder="Presenter, Collaborator, Attendee, Consumer"
1279+
componentRef={(val) => this.patchParticipantRole = val} />
1280+
</div>
1281+
<PrimaryButton className="primary-button"
1282+
iconProps={{ iconName: 'Video', style: { verticalAlign: 'middle', fontSize: 'large' } }}
1283+
text="Update participant role"
1284+
onClick={() => this.updateParticipant()}>
1285+
</PrimaryButton>
1286+
</div>
12341287
</div>
12351288
}
12361289
</div>

Project/src/Utils/Utils.js

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,24 +97,65 @@ export const utils = {
9797
}
9898
throw new Error('Failed to get Teams User Acccess token');
9999
},
100-
createRoom: async (presenterUserId, attendeeUserId, consumerUserId) => {
100+
createRoom: async (pstnDialOutEnabled, presenterUserIds, collaboratorUserIds, attendeeUserIds, consumerUserIds) => {
101101
try {
102+
const data = {};
103+
data.pstnDialOutEnabled = pstnDialOutEnabled;
104+
if (presenterUserIds) {
105+
data.presenterUserIds = presenterUserIds.split(',').map(id => id.trim());
106+
}
107+
if (collaboratorUserIds) {
108+
data.collaboratorUserIds = collaboratorUserIds.split(',').map(id => id.trim());
109+
}
110+
if (attendeeUserIds) {
111+
data.attendeeUserIds = attendeeUserIds.split(',').map(id => id.trim());
112+
}
113+
if (consumerUserIds) {
114+
data.consumerUserIds = consumerUserIds.split(',').map(id => id.trim());
115+
}
116+
102117
const response = await axios({
103118
url: 'createRoom',
104119
method: 'POST',
105120
headers: {
106121
'Accept': 'application/json, text/plain, */*',
107122
'Content-type': 'application/json'
108123
},
109-
data: JSON.stringify({ presenterUserId, attendeeUserId, consumerUserId })
110-
})
111-
124+
data: JSON.stringify(data)
125+
});
126+
console.log('Room created successfully:', response.data);
112127
return response.data.roomId;
113128

114129
} catch (error) {
130+
console.error('Error creating room:', error);
115131
throw error.response.data.message;
116132
}
117133
},
134+
updateParticipant: async (patchRoomId, patchParticipantId, patchParticipantRole) => {
135+
try {
136+
if (!patchRoomId.trim() || !patchParticipantId.trim() || !patchParticipantRole.trim()) {
137+
throw new Error('All parameters (patchRoomId, patchParticipantId, patchParticipantRole) must be non-empty strings without trailing whitespace.');
138+
}
139+
140+
const response = await axios({
141+
url: 'updateParticipant',
142+
method: 'PATCH',
143+
headers: {
144+
'Accept': 'application/json, text/plain, */*',
145+
'Content-type': 'application/json'
146+
},
147+
data: JSON.stringify({
148+
patchRoomId: patchRoomId.trim(),
149+
patchParticipantId: patchParticipantId.trim(),
150+
patchParticipantRole: patchParticipantRole.trim()
151+
})
152+
});
153+
console.log('Participant updated successfully:', response.data);
154+
} catch (error) {
155+
console.error('Error updating participant:', error);
156+
throw error.response?.data?.message || error.message;
157+
}
158+
},
118159
getIdentifierText: (identifier) => {
119160
if (isCommunicationUserIdentifier(identifier)) {
120161
return identifier.communicationUserId;

0 commit comments

Comments
 (0)