Skip to content

Add more Rooms functionality with new Manage Rooms panel #268

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Project/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Project/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"version": "1.0.0",
"private": true,
"dependencies": {
"@azure/communication-calling": "1.33.2-beta.1",
"@azure/communication-calling": "1.34.1-beta.2",
"@azure/communication-calling-effects": "1.1.1-beta.1",
"@azure/communication-common": "^2.3.0",
"@azure/communication-identity": "^1.3.0",
"@azure/communication-network-traversal": "^1.1.0-beta.1",
"@azure/communication-rooms": "1.1.1",
"@azure/communication-rooms": "1.2.0",
"@azure/logger": "^1.0.3",
"@azure/msal-browser": "^2.33.0",
"@azure/msal-node": "^1.17.1",
Expand Down
103 changes: 78 additions & 25 deletions Project/src/MakeCall/MakeCall.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CallClient, LocalVideoStream, Features, CallAgentKind, VideoStreamRende
import { AzureCommunicationTokenCredential, createIdentifierFromRawId} from '@azure/communication-common';
import { PrimaryButton } from '@fluentui/react/lib/Button';
import { TextField } from '@fluentui/react/lib/TextField';
import { MessageBar, MessageBarType } from '@fluentui/react';
import { MessageBar, MessageBarType, Toggle } from '@fluentui/react';
import { Icon } from '@fluentui/react/lib/Icon';
import IncomingCallCard from './IncomingCallCard';
import CallCard from '../MakeCall/CallCard';
Expand Down Expand Up @@ -34,9 +34,13 @@ export default class MakeCall extends React.Component {
this.meetingLink = null;
this.meetingId = null;
this.passcode = null;
this.presenterUserId = null;
this.attendeeUserId = null;
this.consumerUserId = null;
this.presenterUserIds = null;
this.collaboratorUserIds = null;
this.attendeeUserIds = null;
this.consumerUserIds = null;
this.patchRoomId = null;
this.patchParticipantId = null;
this.patchParticipantRole = null;
this.threadId = null;
this.messageId = null;
this.organizerId = null;
Expand All @@ -62,7 +66,8 @@ export default class MakeCall extends React.Component {
showPreCallDiagnostcisResults: false,
showCustomContext: false,
roomId: undefined,
showCreateRoomPanel: false,
roomPstnDialOutEnabled: true,
showManageRoomsPanel: false,
xHeadersCount: 1,
xHeadersMaxCount: 5,
isPreCallDiagnosticsCallInProgress: false,
Expand Down Expand Up @@ -374,14 +379,23 @@ export default class MakeCall extends React.Component {

createRoom = async () => {
try {
const roomId = await utils.createRoom(this.presenterUserId.value, this.attendeeUserId.value, this.consumerUserId.value);
const roomId = await utils.createRoom(this.state.roomPstnDialOutEnabled, this.presenterUserIds.value, this.collaboratorUserIds.value, this.attendeeUserIds.value, this.consumerUserIds.value);
console.log('Room id created: ', roomId);
this.setState({ roomId });
} catch (e) {
console.error('Failed to create a room: ', e);
}
};

updateParticipant = async () => {
try {
await utils.updateParticipant(this.patchRoomId.value, this.patchParticipantId.value, this.patchParticipantRole.value);
console.log('Participant updated successfully');
} catch (e) {
console.error('Failed to update participant ', e);
}
};

joinTeamsMeeting = async (withVideo, micMuted = false) => {
try {
const callOptions = await this.getCallOptions({video: withVideo, micMuted: micMuted});
Expand Down Expand Up @@ -1175,7 +1189,7 @@ this.callAgent.on('incomingCall', async (args) => {
disabled={this.state.call || !this.state.loggedIn}
label="Rooms id"
value={ this.state.roomId }
placeholder="<GUID>"
placeholder="<Room ID (starts with 9)>"
onChange={(e) => this.setState({ roomId: e.target.value })}/>
</div>
</div>
Expand All @@ -1193,44 +1207,83 @@ this.callAgent.on('incomingCall', async (args) => {
</PrimaryButton>
<PrimaryButton className="primary-button"
iconProps={{ iconName: 'Group', style: { verticalAlign: 'middle', fontSize: 'large' } }}
text="Create a room"
disabled={this.state.call || !this.state.loggedIn}
onClick={() => this.setState({ showCreateRoomPanel: !this.state.showCreateRoomPanel })}>
text="Manage Rooms"
onClick={() => this.setState({ showManageRoomsPanel: !this.state.showManageRoomsPanel })}>
</PrimaryButton>
</div>
{
this.state.showCreateRoomPanel &&
this.state.showManageRoomsPanel &&
<div className="mt-5">
<h2 className="mb-0">Create a Room</h2>
<h2 className="mb-0">Manage Rooms</h2>
<h3 className="mb-0">Create a Room</h3>
<div className="ms-Grid-row">
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<Toggle className="mb-3 mt-0"
checked={this.state.roomPstnDialOutEnabled}
label="PSTN Dial Out Enabled"
onText="True"
offText="False"
onClick={() => {
console.log(this.state.roomPstnDialOutEnabled);
this.setState({roomPstnDialOutEnabled: !this.state.roomPstnDialOutEnabled})
}} />
</div>
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
disabled={this.state.call || !this.state.loggedIn}
label="Presenter user id"
label="Presenter user ids (comma delimited)"
placeholder="8:acs:<ACS resource ID>_<GUID>"
componentRef={(val) => this.presenterUserId = val} />
componentRef={(val) => this.presenterUserIds = val} />
</div>
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
disabled={this.state.call || !this.state.loggedIn}
label="Attendee user id"
label="Collaborator user ids (comma delimited)"
placeholder="8:acs:<ACS resource ID>_<GUID>"
componentRef={(val) => this.attendeeUserId = val} />
componentRef={(val) => this.collaboratorUserIds = val} />
</div>
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
disabled={this.state.call || !this.state.loggedIn}
label="Consumer user id"
label="Attendee user ids (comma delimited)"
placeholder="8:acs:<ACS resource ID>_<GUID>"
componentRef={(val) => this.consumerUserId = val} />
componentRef={(val) => this.attendeeUserIds = val} />
</div>
</div>
<PrimaryButton className="primary-button"
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
label="Consumer user ids (comma delimited)"
placeholder="8:acs:<ACS resource ID>_<GUID>"
componentRef={(val) => this.consumerUserIds = val} />
</div>
<PrimaryButton className="primary-button"
iconProps={{ iconName: 'Video', style: { verticalAlign: 'middle', fontSize: 'large' } }}
text="Create room"
disabled={this.state.call || !this.state.loggedIn}
onClick={() => this.createRoom()}>
</PrimaryButton>
</PrimaryButton>
</div>
<h3 className="mb-0">Update a Participant</h3>
<div className="ms-Grid-row">
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
label="Room ID"
placeholder="Room ID (9xxxxxx)"
componentRef={(val) => this.patchRoomId = val} />
</div>
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
label="Participant user ID"
placeholder="8:acs:<ACS resource ID>_<GUID>"
componentRef={(val) => this.patchParticipantId = val} />
</div>
<div className="md-Grid-col ml-2 ms-sm11 ms-md11 ms-lg9 ms-xl9 ms-xxl11">
<TextField className="mb-3 mt-0"
label="Role"
placeholder="Presenter, Collaborator, Attendee, Consumer"
componentRef={(val) => this.patchParticipantRole = val} />
</div>
<PrimaryButton className="primary-button"
iconProps={{ iconName: 'Video', style: { verticalAlign: 'middle', fontSize: 'large' } }}
text="Update participant role"
onClick={() => this.updateParticipant()}>
</PrimaryButton>
</div>
</div>
}
</div>
Expand Down
49 changes: 45 additions & 4 deletions Project/src/Utils/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,65 @@ export const utils = {
}
throw new Error('Failed to get Teams User Acccess token');
},
createRoom: async (presenterUserId, attendeeUserId, consumerUserId) => {
createRoom: async (pstnDialOutEnabled, presenterUserIds, collaboratorUserIds, attendeeUserIds, consumerUserIds) => {
try {
const data = {};
data.pstnDialOutEnabled = pstnDialOutEnabled;
if (presenterUserIds) {
data.presenterUserIds = presenterUserIds.split(',').map(id => id.trim());
}
if (collaboratorUserIds) {
data.collaboratorUserIds = collaboratorUserIds.split(',').map(id => id.trim());
}
if (attendeeUserIds) {
data.attendeeUserIds = attendeeUserIds.split(',').map(id => id.trim());
}
if (consumerUserIds) {
data.consumerUserIds = consumerUserIds.split(',').map(id => id.trim());
}

const response = await axios({
url: 'createRoom',
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-type': 'application/json'
},
data: JSON.stringify({ presenterUserId, attendeeUserId, consumerUserId })
})

data: JSON.stringify(data)
});
console.log('Room created successfully:', response.data);
return response.data.roomId;

} catch (error) {
console.error('Error creating room:', error);
throw error.response.data.message;
}
},
updateParticipant: async (patchRoomId, patchParticipantId, patchParticipantRole) => {
try {
if (!patchRoomId.trim() || !patchParticipantId.trim() || !patchParticipantRole.trim()) {
throw new Error('All parameters (patchRoomId, patchParticipantId, patchParticipantRole) must be non-empty strings without trailing whitespace.');
}

const response = await axios({
url: 'updateParticipant',
method: 'PATCH',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-type': 'application/json'
},
data: JSON.stringify({
patchRoomId: patchRoomId.trim(),
patchParticipantId: patchParticipantId.trim(),
patchParticipantRole: patchParticipantRole.trim()
})
});
console.log('Participant updated successfully:', response.data);
} catch (error) {
console.error('Error updating participant:', error);
throw error.response?.data?.message || error.message;
}
},
getIdentifierText: (identifier) => {
if (isCommunicationUserIdentifier(identifier)) {
return identifier.communicationUserId;
Expand Down
Loading
Loading