Skip to content

Commit 228c9b0

Browse files
Merge pull request #272630 from emlynmac/emlyn/js-docs-teams-shortlink-update
Update chat interop QuickStart documentation for JavaScript
2 parents f9884c1 + 615b381 commit 228c9b0

File tree

1 file changed

+97
-93
lines changed

1 file changed

+97
-93
lines changed

articles/communication-services/quickstarts/chat/includes/meeting-interop-javascript.md

Lines changed: 97 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ npm install @azure/communication-common --save
4444

4545
npm install @azure/communication-identity --save
4646

47-
npm install @azure/communication-signaling --save
48-
4947
npm install @azure/communication-chat --save
5048

5149
npm install @azure/communication-calling --save
@@ -58,7 +56,7 @@ The `--save` option lists the library as a dependency in your **package.json** f
5856
This quickstart uses Webpack to bundle the application assets. Run the following command to install the Webpack, webpack-cli and webpack-dev-server npm packages and list them as development dependencies in your **package.json**:
5957

6058
```console
61-
npm install webpack@4.42.0 webpack-cli@3.3.11 webpack-dev-server@3.10.3 --save-dev
59+
npm install webpack@5.89.0 webpack-cli@5.1.4 webpack-dev-server@4.15.1 --save-dev
6260
```
6361

6462
Create an **index.html** file in the root directory of your project. We use this file to configure a basic layout that will allow the user to join a meeting and start chatting.
@@ -145,9 +143,7 @@ A chat pop-up appears at the bottom of the page. It can be used to send messages
145143
<h4>Azure Communication Services</h4>
146144
<h1>Calling and Chat Quickstart</h1>
147145
<input id="teams-link-input" type="text" placeholder="Teams meeting link"
148-
style="margin-bottom:1em; width: 300px;" />
149-
<input id="thread-id-input" type="text" placeholder="Chat thread id"
150-
style="margin-bottom:1em; width: 300px;" />
146+
style="margin-bottom:1em; width: 400px;" />
151147
<p>Call state <span style="font-weight: bold" id="call-state">-</span></p>
152148
<div>
153149
<button id="join-meeting-button" type="button">
@@ -175,10 +171,9 @@ Replace the content of the client.js file with the following snippet.
175171

176172
Within the snippet, replace
177173
- `SECRET_CONNECTION_STRING` with your Communication Service's connection string
178-
- `ENDPOINT_URL` with your Communication Service's endpoint url
179174

180175
```javascript
181-
import { CallClient, CallAgent } from "@azure/communication-calling";
176+
import { CallClient } from "@azure/communication-calling";
182177
import { AzureCommunicationTokenCredential } from "@azure/communication-common";
183178
import { CommunicationIdentityClient } from "@azure/communication-identity";
184179
import { ChatClient } from "@azure/communication-chat";
@@ -188,133 +183,152 @@ let callAgent;
188183
let chatClient;
189184
let chatThreadClient;
190185

191-
const meetingLinkInput = document.getElementById('teams-link-input');
192-
const threadIdInput = document.getElementById('thread-id-input');
186+
const meetingLinkInput = document.getElementById("teams-link-input");
193187
const callButton = document.getElementById("join-meeting-button");
194188
const hangUpButton = document.getElementById("hang-up-button");
195-
const callStateElement = document.getElementById('call-state');
189+
const callStateElement = document.getElementById("call-state");
196190

197191
const messagesContainer = document.getElementById("messages-container");
198192
const chatBox = document.getElementById("chat-box");
199193
const sendMessageButton = document.getElementById("send-message");
200-
const messagebox = document.getElementById("message-box");
194+
const messageBox = document.getElementById("message-box");
201195

202-
var userId = '';
203-
var lastMessage = '';
204-
var previousMessage = '';
196+
var userId = "";
197+
var messages = "";
198+
var chatThreadId = "";
205199

206200
async function init() {
207201
const connectionString = "<SECRET_CONNECTION_STRING>";
208-
const endpointUrl = "<ENDPOINT_URL>";
202+
const endpointUrl = connectionString.split(";")[0];
209203

210204
const identityClient = new CommunicationIdentityClient(connectionString);
211205

212206
let identityResponse = await identityClient.createUser();
213207
userId = identityResponse.communicationUserId;
214208
console.log(`\nCreated an identity with ID: ${identityResponse.communicationUserId}`);
215209

216-
let tokenResponse = await identityClient.getToken(identityResponse, [
217-
"voip",
218-
"chat",
219-
]);
210+
let tokenResponse = await identityClient.getToken(identityResponse, ["voip", "chat"]);
220211

221212
const { token, expiresOn } = tokenResponse;
222213
console.log(`\nIssued an access token that expires at: ${expiresOn}`);
223214
console.log(token);
224215

225216
const callClient = new CallClient();
226217
const tokenCredential = new AzureCommunicationTokenCredential(token);
218+
227219
callAgent = await callClient.createCallAgent(tokenCredential);
228220
callButton.disabled = false;
221+
chatClient = new ChatClient(endpointUrl, new AzureCommunicationTokenCredential(token));
229222

230-
chatClient = new ChatClient(
231-
endpointUrl,
232-
new AzureCommunicationTokenCredential(token)
233-
);
234-
235-
console.log('Azure Communication Chat client created!');
223+
console.log("Azure Communication Chat client created!");
236224
}
237225

238226
init();
239227

228+
const joinCall = (urlString, callAgent) => {
229+
const url = new URL(urlString);
230+
console.log(url);
231+
if (url.pathname.startsWith("/meet")) {
232+
// Short teams URL, so for now call meetingID and pass code API
233+
return callAgent.join({
234+
meetingId: url.pathname.split("/").pop(),
235+
passcode: url.searchParams.get("p"),
236+
});
237+
} else {
238+
return callAgent.join({ meetingLink: urlString }, {});
239+
}
240+
};
241+
240242
callButton.addEventListener("click", async () => {
241243
// join with meeting link
242-
call = callAgent.join({meetingLink: meetingLinkInput.value}, {});
244+
try {
245+
call = joinCall(meetingLinkInput.value, callAgent);
246+
} catch {
247+
throw new Error("Could not join meeting - have you set your connection string?");
248+
}
249+
250+
// Chat thread ID is provided from the call info, after connection.
251+
call.on("stateChanged", async () => {
252+
callStateElement.innerText = call.state;
253+
254+
if (call.state === "Connected" && !chatThreadClient) {
255+
chatThreadId = call.info?.threadId;
256+
chatThreadClient = chatClient.getChatThreadClient(chatThreadId);
257+
258+
chatBox.style.display = "block";
259+
messagesContainer.innerHTML = messages;
260+
261+
// open notifications channel
262+
await chatClient.startRealtimeNotifications();
263+
264+
// subscribe to new message notifications
265+
chatClient.on("chatMessageReceived", (e) => {
266+
console.log("Notification chatMessageReceived!");
267+
268+
// check whether the notification is intended for the current thread
269+
if (chatThreadId != e.threadId) {
270+
return;
271+
}
272+
273+
if (e.sender.communicationUserId != userId) {
274+
renderReceivedMessage(e.message);
275+
} else {
276+
renderSentMessage(e.message);
277+
}
278+
});
279+
}
280+
});
243281

244-
call.on('stateChanged', () => {
245-
callStateElement.innerText = call.state;
246-
})
247282
// toggle button and chat box states
248-
chatBox.style.display = "block";
249283
hangUpButton.disabled = false;
250284
callButton.disabled = true;
251285

252-
messagesContainer.innerHTML = "";
253-
254286
console.log(call);
255-
256-
// open notifications channel
257-
await chatClient.startRealtimeNotifications();
258-
259-
// subscribe to new message notifications
260-
chatClient.on("chatMessageReceived", (e) => {
261-
console.log("Notification chatMessageReceived!");
262-
263-
// check whether the notification is intended for the current thread
264-
if (threadIdInput.value != e.threadId) {
265-
return;
266-
}
267-
268-
if (e.sender.communicationUserId != userId) {
269-
renderReceivedMessage(e.message);
270-
}
271-
else {
272-
renderSentMessage(e.message);
273-
}
274-
});
275-
276-
chatThreadClient = await chatClient.getChatThreadClient(threadIdInput.value);
277287
});
278288

279289
async function renderReceivedMessage(message) {
280-
previousMessage = lastMessage;
281-
lastMessage = '<div class="container lighter">' + message + '</div>';
282-
messagesContainer.innerHTML = previousMessage + lastMessage;
290+
messages += '<div class="container lighter">' + message + "</div>";
291+
messagesContainer.innerHTML = messages;
283292
}
284293

285294
async function renderSentMessage(message) {
286-
previousMessage = lastMessage;
287-
lastMessage = '<div class="container darker">' + message + '</div>';
288-
messagesContainer.innerHTML = previousMessage + lastMessage;
295+
messages += '<div class="container darker">' + message + "</div>";
296+
messagesContainer.innerHTML = messages;
289297
}
290298

291-
hangUpButton.addEventListener("click", async () =>
292-
{
293-
// end the current call
294-
await call.hangUp();
299+
hangUpButton.addEventListener("click", async () => {
300+
// end the current call
301+
await call.hangUp();
302+
// Stop notifications
303+
chatClient.stopRealtimeNotifications();
295304

296-
// toggle button states
297-
hangUpButton.disabled = true;
298-
callButton.disabled = false;
299-
callStateElement.innerText = '-';
305+
// toggle button states
306+
hangUpButton.disabled = true;
307+
callButton.disabled = false;
308+
callStateElement.innerText = "-";
300309

301-
// toggle chat states
302-
chatBox.style.display = "none";
303-
messages = "";
304-
});
310+
// toggle chat states
311+
chatBox.style.display = "none";
312+
messages = "";
313+
// Remove local ref
314+
chatThreadClient = undefined;
315+
});
305316

306-
sendMessageButton.addEventListener("click", async () =>
307-
{
308-
let message = messagebox.value;
317+
sendMessageButton.addEventListener("click", async () => {
318+
let message = messageBox.value;
309319

310-
let sendMessageRequest = { content: message };
311-
let sendMessageOptions = { senderDisplayName : 'Jack' };
312-
let sendChatMessageResult = await chatThreadClient.sendMessage(sendMessageRequest, sendMessageOptions);
313-
let messageId = sendChatMessageResult.id;
320+
let sendMessageRequest = { content: message };
321+
let sendMessageOptions = { senderDisplayName: "Jack" };
322+
let sendChatMessageResult = await chatThreadClient.sendMessage(
323+
sendMessageRequest,
324+
sendMessageOptions
325+
);
326+
let messageId = sendChatMessageResult.id;
327+
328+
messageBox.value = "";
329+
console.log(`Message sent!, message id:${messageId}`);
330+
});
314331

315-
messagebox.value = '';
316-
console.log(`Message sent!, message id:${messageId}`);
317-
});
318332
```
319333
320334
Display names of the chat thread participants aren't set by the Teams client. The names are returned as null in the API for listing participants, in the `participantsAdded` event and in the `participantsRemoved` event. The display names of the chat participants can be retrieved from the `remoteParticipants` field of the `call` object. On receiving a notification about a roster change, you can use this code to retrieve the name of the user that was added or removed:
@@ -323,16 +337,6 @@ Display names of the chat thread participants aren't set by the Teams client. Th
323337
var displayName = call.remoteParticipants.find(p => p.identifier.communicationUserId == '<REMOTE_USER_ID>').displayName;
324338
```
325339
326-
## Get a Teams meeting chat thread for a Communication Services user
327-
328-
The Teams meeting details can be retrieved using Graph APIs, detailed in [Graph documentation](/graph/api/onlinemeeting-createorget?tabs=http&view=graph-rest-beta&preserve-view=true). The Communication Services Calling SDK accepts a full Teams meeting link or a meeting ID. They're returned as part of the `onlineMeeting` resource, accessible under the [`joinWebUrl` property](/graph/api/resources/onlinemeeting?view=graph-rest-beta&preserve-view=true)
329-
330-
With the [Graph APIs](/graph/api/onlinemeeting-createorget?tabs=http&view=graph-rest-beta&preserve-view=true), you can also obtain the `threadID`. The response contains a `chatInfo` object with the `threadID`.
331-
332-
You can also get the required meeting information and thread ID from the **Join Meeting** URL in the Teams meeting invite itself.
333-
A Teams meeting link looks like this: `https://teams.microsoft.com/l/meetup-join/meeting_chat_thread_id/1606337455313?context=some_context_here`. The `threadId` is where `meeting_chat_thread_id` is in the link. Ensure that the `meeting_chat_thread_id` is unescaped before use. It should be in the following format: `19:meeting_ZWRhZDY4ZGUtYmRlNS00OWZaLTlkZTgtZWRiYjIxOWI2NTQ4@thread.v2`
334-
335-
336340
## Run the code
337341
338342
Webpack users can use the `webpack-dev-server` to build and run your app. Run the following command to bundle your application host on a local webserver:

0 commit comments

Comments
 (0)