diff --git a/conversations/add-participant/addParticipant.js b/conversations/add-participant/addParticipant.js new file mode 100644 index 000000000..d1aa44f69 --- /dev/null +++ b/conversations/add-participant/addParticipant.js @@ -0,0 +1,17 @@ +/* Adding Participants (chat and non-chat) */ + +// add chat participant to the conversation by its identity +await conversation.add("identity"); + +// add a non-chat participant to the conversation +const proxyAddress = "+11222333"; +const address = "+12345678"; +await conversation.addNonChatParticipant(proxyAddress, address); + +// adds yourself as a conversations sdk user to this conversation +// use after creating the conversation from the SDK +await conversation.join(); + +conversation.on("participantJoined", (participant) => { + // fired when a participant has joined the conversation +}); diff --git a/conversations/add-participant/addParticipant.ts b/conversations/add-participant/addParticipant.ts new file mode 100644 index 000000000..2bcdb6c7c --- /dev/null +++ b/conversations/add-participant/addParticipant.ts @@ -0,0 +1,18 @@ +/* Adding Participants (chat and non-chat) */ +import {Participant} from "@twilio/conversations"; + +// add chat participant to the conversation by its identity +await conversation.add("identity"); + +// add a non-chat participant to the conversation +const proxyAddress: string = "+11222333"; +const address: string = "+12345678"; +await conversation.addNonChatParticipant(proxyAddress, address); + +// adds yourself as a conversations sdk user to this conversation +// use after creating the conversation from the SDK +await conversation.join(); + +conversation.on("participantJoined", (participant: Participant) => { + // fired when a participant has joined the conversation +}); diff --git a/conversations/attributes/attributes.js b/conversations/attributes/attributes.js new file mode 100644 index 000000000..c51933d91 --- /dev/null +++ b/conversations/attributes/attributes.js @@ -0,0 +1,24 @@ +/* Using Attributes */ + +// add attributes to a message +const message = await conversation.prepareMessage().setBody("message text"); + +await conversation.setAttributes("attribute"); +await conversation.setAttributes(2); +await conversation.setAttributes(true); +await conversation.setAttributes({attributeKey: "attributeValue"}); +await conversation.setAttributes(["attribute", "anotherAttribute"]); + +// get the attributes +const messageAttributes = message.attributes; + +// add participant to the conversation with attributes +await conversation.add("identity", "attribute"); +await conversation.add("identity", 2); +await conversation.add("identity", true); +await conversation.add("identity", {attributeKey: "attributeValue"}); +await conversation.add("identity", ["attribute", "anotherAttribute"]); + +// get the attributes +const participant = await conversation.getParticipantByIdentity("identity"); +const participantAttributes = participant.attributes; diff --git a/conversations/attributes/attributes.ts b/conversations/attributes/attributes.ts new file mode 100644 index 000000000..b5777c297 --- /dev/null +++ b/conversations/attributes/attributes.ts @@ -0,0 +1,26 @@ +/* Using Attributes */ + +import {MessageBuilder, Participant, JSONValue} from "@twilio/conversations"; + +// add attributes to a message +const message: MessageBuilder = await conversation.prepareMessage().setBody("message text"); + +await conversation.setAttributes("attribute"); +await conversation.setAttributes(2); +await conversation.setAttributes(true); +await conversation.setAttributes({attributeKey: "attributeValue"}); +await conversation.setAttributes(["attribute", "anotherAttribute"]); + +// get the attributes +const messageAttributes: JSONValue = message.attributes; + +// add participant to the conversation with attributes +await conversation.add("identity", "attribute"); +await conversation.add("identity", 2); +await conversation.add("identity", true); +await conversation.add("identity", {attributeKey: "attributeValue"}); +await conversation.add("identity", ["attribute", "anotherAttribute"]); + +// get the attributes +const participant: Participant = await conversation.getParticipantByIdentity("identity"); +const participantAttributes: JSONValue = participant.attributes; diff --git a/conversations/create-conversation/createConversation.js b/conversations/create-conversation/createConversation.js new file mode 100644 index 000000000..5a14086a1 --- /dev/null +++ b/conversations/create-conversation/createConversation.js @@ -0,0 +1,8 @@ +/* Creating Conversation */ + +// create new conversation, all the parameters are optional +await client.createConversation({ + attributes: {}, + friendlyName: "new conversation", + uniqueName: "new conversation", +}); diff --git a/conversations/create-conversation/createConversation.ts b/conversations/create-conversation/createConversation.ts new file mode 100644 index 000000000..5a14086a1 --- /dev/null +++ b/conversations/create-conversation/createConversation.ts @@ -0,0 +1,8 @@ +/* Creating Conversation */ + +// create new conversation, all the parameters are optional +await client.createConversation({ + attributes: {}, + friendlyName: "new conversation", + uniqueName: "new conversation", +}); diff --git a/conversations/deleting/deleting.js b/conversations/deleting/deleting.js new file mode 100644 index 000000000..7e9f39902 --- /dev/null +++ b/conversations/deleting/deleting.js @@ -0,0 +1,16 @@ +/* Deleting and updating Conversations/Messages/Participants */ + +/* Conversations */ + +// destroys the conversation, with all its messages and attached media and removes all participants +await conversation.delete(); + +/* Messages */ + +// remove a message from the conversation, destroying any attached media +await message.remove(); + +/* Participants */ + +// remove participant from the conversation +await participant.remove(); diff --git a/conversations/deleting/deleting.ts b/conversations/deleting/deleting.ts new file mode 100644 index 000000000..fc2b3dea5 --- /dev/null +++ b/conversations/deleting/deleting.ts @@ -0,0 +1,16 @@ +/* Deleting Conversations/Messages/Participants */ + +/* Conversations */ + +// destroys the conversation, with all its messages and attached media and removes all participants +await conversation.delete(); + +/* Messages */ + +// remove a message from the conversation, destroying any attached media +await message.remove(); + +/* Participants */ + +// remove participant from the conversation +await participant.remove(); diff --git a/conversations/delivery-receipt-error/deliveryReceiptError.js b/conversations/delivery-receipt-error/deliveryReceiptError.js new file mode 100644 index 000000000..ae063fa4f --- /dev/null +++ b/conversations/delivery-receipt-error/deliveryReceiptError.js @@ -0,0 +1,29 @@ +/* Checking delivery receipts for errors */ + +// get the list of aggregated delivery receipts +const aggregatedDeliveryReceipt = message.aggregatedDeliveryReceipt; + +// retrieve delivery receipt status +if (aggregatedDeliveryReceipt.failed !== "none" || aggregatedDeliveryReceipt.undelivered !== "none") { + // handle error +} + +// get the list of delivery receipts +const detailedDeliveryReceipts = await message.getDetailedDeliveryReceipts(); + +detailedDeliveryReceipts.map((detailedDeliveryReceipt) => { + // check delivery receipt status + if (!detailedDeliveryReceipt.status === "undelivered" && !detailedDeliveryReceipt.status === "failed") { + return; + } + + // handle error. the error codes page: https://www.twilio.com/docs/sms/api/message-resource#delivery-related-errors + if (detailedDeliveryReceipt.errorCode === 30006) { + alert("The destination number is unable to receive this message."); + return; + } + + if (detailedDeliveryReceipt.errorCode === 30007) { + alert("Your message was flagged as objectionable by the carrier."); + } +}); diff --git a/conversations/delivery-receipt-error/deliveryReceiptError.ts b/conversations/delivery-receipt-error/deliveryReceiptError.ts new file mode 100644 index 000000000..65754705c --- /dev/null +++ b/conversations/delivery-receipt-error/deliveryReceiptError.ts @@ -0,0 +1,31 @@ +/* Checking delivery receipts for errors */ + +// get the list of aggregated delivery receipts +import {AggregatedDeliveryReceipt, DetailedDeliveryReceipt} from "@twilio/conversations"; + +const aggregatedDeliveryReceipt: AggregatedDeliveryReceipt = message.aggregatedDeliveryReceipt; + +// retrieve delivery receipt status +if (aggregatedDeliveryReceipt.failed !== "none" || aggregatedDeliveryReceipt.undelivered !== "none") { + // handle error +} + +// get the list of delivery receipts +const detailedDeliveryReceipts: DetailedDeliveryReceipt[] = await message.getDetailedDeliveryReceipts(); + +detailedDeliveryReceipts.map((detailedDeliveryReceipt: DetailedDeliveryReceipt) => { + // check delivery receipt status + if (!detailedDeliveryReceipt.status === "undelivered" && !detailedDeliveryReceipt.status === "failed") { + return; + } + + // handle error. the error codes page: https://www.twilio.com/docs/sms/api/message-resource#delivery-related-errors + if (detailedDeliveryReceipt.errorCode === 30006) { + alert("The destination number is unable to receive this message."); + return; + } + + if (detailedDeliveryReceipt.errorCode === 30007) { + alert("Your message was flagged as objectionable by the carrier."); + } +}); diff --git a/conversations/delivery-receipts/deliveryReceipts.js b/conversations/delivery-receipts/deliveryReceipts.js new file mode 100644 index 000000000..429144a71 --- /dev/null +++ b/conversations/delivery-receipts/deliveryReceipts.js @@ -0,0 +1,25 @@ +/* Retrieving Delivery Receipts (aggregated and detailed) for rendering */ + +const aggregatedDeliveryReceipt = message.aggregatedDeliveryReceipt; + +// get amount (DeliveryAmount) of participants with particular delivery status +const deliveredReceipts = aggregatedDeliveryReceipt?.delivered; +const failedReceipts = aggregatedDeliveryReceipt?.failed; +const readReceipts = aggregatedDeliveryReceipt?.read; +const sentReceipts = aggregatedDeliveryReceipt?.sent; +const undeliveredReceipts = aggregatedDeliveryReceipt?.undelivered; +// get the amount of participants which have the status for the message +const totalReceipts = aggregatedDeliveryReceipt?.total; + +if (undeliveredReceipts !== "none") { + // some delivery problems + alert(`Out of ${totalReceipts} sent messages, ${deliveredReceipts} were delivered, ${failedReceipts} have failed.`); +} + +// get the list of of delivery receipts +const detailedDeliveryReceipts = await message.getDetailedDeliveryReceipts(); + +detailedDeliveryReceipts.map((detailedDeliveryReceipt) => { + // get status of the delivery receipts + const receiptStatus = detailedDeliveryReceipt.status; +}); diff --git a/conversations/delivery-receipts/deliveryReceipts.ts b/conversations/delivery-receipts/deliveryReceipts.ts new file mode 100644 index 000000000..23a5e880b --- /dev/null +++ b/conversations/delivery-receipts/deliveryReceipts.ts @@ -0,0 +1,32 @@ +/* Retrieving Delivery Receipts (aggregated and detailed) for rendering */ + +import { + AggregatedDeliveryReceipt, + DeliveryAmount, + DeliveryStatus, + DetailedDeliveryReceipt +} from "@twilio/conversations"; + +const aggregatedDeliveryReceipt: AggregatedDeliveryReceipt | null = message.aggregatedDeliveryReceipt; + +// get amount (DeliveryAmount) of participants with particular delivery status +const deliveredReceipts: DeliveryAmount = aggregatedDeliveryReceipt?.delivered; +const failedReceipts: DeliveryAmount = aggregatedDeliveryReceipt?.failed; +const readReceipts: DeliveryAmount = aggregatedDeliveryReceipt?.read; +const sentReceipts: DeliveryAmount = aggregatedDeliveryReceipt?.sent; +const undeliveredReceipts: DeliveryAmount = aggregatedDeliveryReceipt?.undelivered; +// get the amount of participants which have the status for the message +const totalReceipts: number = aggregatedDeliveryReceipt?.total; + +if (undeliveredReceipts !== "none") { + // some delivery problems + alert(`Out of ${totalReceipts} sent messages, ${deliveredReceipts} were delivered, ${failedReceipts} have failed.`); +} + +// get the list of of delivery receipts +const detailedDeliveryReceipts: DetailedDeliveryReceipt[] = await message.getDetailedDeliveryReceipts(); + +detailedDeliveryReceipts.map((detailedDeliveryReceipt) => { + // get status of the delivery receipts + const receiptStatus: DeliveryStatus = detailedDeliveryReceipt.status; +}); diff --git a/conversations/event-handlers/eventHandlers.js b/conversations/event-handlers/eventHandlers.js new file mode 100644 index 000000000..81b7596db --- /dev/null +++ b/conversations/event-handlers/eventHandlers.js @@ -0,0 +1,13 @@ +/* event handler examples */ + +client.on("conversationUpdated", ({conversation, updateReasons}) => { + // Fired when the attributes or the metadata of a conversation have been updated +}); + +conversation.on("messageUpdated", ({message, updateReasons}) => { + // Fired when data of a message has been updated. +}); + +participant.on("updated", ({participant, updateReasons}) => { + // Fired when the fields of the participant have been updated. +}); diff --git a/conversations/event-handlers/eventHandlers.ts b/conversations/event-handlers/eventHandlers.ts new file mode 100644 index 000000000..d8ab2cd06 --- /dev/null +++ b/conversations/event-handlers/eventHandlers.ts @@ -0,0 +1,31 @@ +/* event handler examples */ + +import { + Conversation, + ConversationUpdateReason, + Message, + MessageUpdateReason, + Participant, + ParticipantUpdateReason +} from "@twilio/conversations"; + +client.on("conversationUpdated", ({conversation, updateReasons}: { + conversation: Conversation, + updateReasons: ConversationUpdateReason[] +}) => { + // Fired when the attributes or the metadata of a conversation have been updated +}); + +message.on("updated", ({message, updateReasons}: { + message: Message, + updateReasons: MessageUpdateReason[] +}) => { + // Fired when data of a message has been updated. +}); + +participant.on("updated", ({participant, updateReasons}: { + participant: Participant, + updateReasons: ParticipantUpdateReason[] +}) => { + // Fired when the fields of the participant have been updated. +}); diff --git a/conversations/get-conversation/getConversation.js b/conversations/get-conversation/getConversation.js new file mode 100644 index 000000000..6d07cc181 --- /dev/null +++ b/conversations/get-conversation/getConversation.js @@ -0,0 +1,7 @@ +/* Get Conversation by SID/Unique Name */ + +// by SID +const conversation = await client.getConversationBySid("bar"); + +// by Unique Name +const conversation = await client.getConversationByUniqueName("foo"); diff --git a/conversations/get-conversation/getConversation.ts b/conversations/get-conversation/getConversation.ts new file mode 100644 index 000000000..9184ebc0c --- /dev/null +++ b/conversations/get-conversation/getConversation.ts @@ -0,0 +1,8 @@ +/* Get Conversation by SID/Unique Name */ +import {Conversation} from "@twilio/conversations"; + +// by SID +const conversation: Conversation = await client.getConversationBySid("bar"); + +// by Unique Name +const conversation: Conversation = await client.getConversationByUniqueName("foo"); diff --git a/conversations/handle-client-state-change/handleClientStateChange.js b/conversations/handle-client-state-change/handleClientStateChange.js new file mode 100644 index 000000000..e04328706 --- /dev/null +++ b/conversations/handle-client-state-change/handleClientStateChange.js @@ -0,0 +1,5 @@ +/* Handle client state change */ + +client.on("connectionStateChanged", ({state}) => { + // handle new connection state +}); diff --git a/conversations/handle-client-state-change/handleClientStateChange.ts b/conversations/handle-client-state-change/handleClientStateChange.ts new file mode 100644 index 000000000..65b5d1d48 --- /dev/null +++ b/conversations/handle-client-state-change/handleClientStateChange.ts @@ -0,0 +1,9 @@ +/* Handle client state change */ + +import {ConnectionState} from "@twilio/conversations"; + +client.on("connectionStateChanged", ({state}: { + state: ConnectionState +}) => { + // handle new connection state +}); diff --git a/conversations/initialization/initialization.js b/conversations/initialization/initialization.js new file mode 100644 index 000000000..ba12d2583 --- /dev/null +++ b/conversations/initialization/initialization.js @@ -0,0 +1,14 @@ +/* Initialization */ +import {Client} from "@twilio/conversations"; + +const client = new Client("token"); +client.on("stateChanged", (state) => { + if (state === "failed") { + // The client failed to initialize + return; + } + + if (state === "initialized") { + // Use the client + } +}); diff --git a/conversations/initialization/initialization.ts b/conversations/initialization/initialization.ts new file mode 100644 index 000000000..ade917f06 --- /dev/null +++ b/conversations/initialization/initialization.ts @@ -0,0 +1,14 @@ +/* Initialization */ +import {Client, State} from "@twilio/conversations"; + +const client: Client = new Client("token"); +client.on('stateChanged', (state: State) => { + if (state === "failed") { + // The client failed to initialize + return; + } + + if (state === 'initialized') { + // Use the client + } +}); diff --git a/conversations/listening-to-conversation/listeningToConversation.js b/conversations/listening-to-conversation/listeningToConversation.js new file mode 100644 index 000000000..80976885d --- /dev/null +++ b/conversations/listening-to-conversation/listeningToConversation.js @@ -0,0 +1,20 @@ +/* Listening to Conversation state change (inactive/closed) */ + +client.on("conversationUpdated", ({conversation, updateReasons}) => { + if (!updateReasons.includes("state")) { + // conversation state was not updated + return; + } + + if (conversation.state.current === "inactive") { + // handle inactive conversation + } + + if (conversation.state.current === "closed") { + // handle closed conversation + } +}); + +client.on("conversationAdded", (conversation) => { + // event triggers when new conversation was created or a conversation becomes visible to the client +}); diff --git a/conversations/listening-to-conversation/listeningToConversation.ts b/conversations/listening-to-conversation/listeningToConversation.ts new file mode 100644 index 000000000..d6179248e --- /dev/null +++ b/conversations/listening-to-conversation/listeningToConversation.ts @@ -0,0 +1,24 @@ +/* Listening to Conversation state change (inactive/closed) */ +import {Conversation, ConversationUpdateReason} from "@twilio/conversations"; + +client.on("conversationUpdated", ({conversation, updateReasons}: { + conversation: Conversation, + updateReasons: ConversationUpdateReason[] +}) => { + if (!updateReasons.includes("state")) { + // conversation state was not updated + return; + } + + if (conversation.state.current === "inactive") { + // handle inactive conversation + } + + if (conversation.state.current === "closed") { + // handle closed conversation + } +}); + +client.on("conversationAdded", (conversation: Conversation) => { + // event triggers when new conversation was created or a conversation becomes visible to the client +}); diff --git a/conversations/listing-conversations/listingConversations.js b/conversations/listing-conversations/listingConversations.js new file mode 100644 index 000000000..61c84c5c9 --- /dev/null +++ b/conversations/listing-conversations/listingConversations.js @@ -0,0 +1,5 @@ +// get the conversations paginator +let conversationsPaginator = await client.getSubscribedConversations(); + +// get conversations +const conversations = conversationsPaginator.items; diff --git a/conversations/listing-conversations/listingConversations.ts b/conversations/listing-conversations/listingConversations.ts new file mode 100644 index 000000000..e2febdb92 --- /dev/null +++ b/conversations/listing-conversations/listingConversations.ts @@ -0,0 +1,7 @@ +import { Conversation, Paginator } from "@twilio/conversations"; + +// get the conversations paginator +let conversationsPaginator: Paginator = await client.getSubscribedConversations(); + +// get conversations +const conversations: Conversation[] = conversationsPaginator.items; diff --git a/conversations/listing-messages/listingMessages.js b/conversations/listing-messages/listingMessages.js new file mode 100644 index 000000000..a002a6d8c --- /dev/null +++ b/conversations/listing-messages/listingMessages.js @@ -0,0 +1,11 @@ +/* get the latest messages of the conversation. optional arguments: + pageSize | 30, + anchor | "end", + direction | "backwards" + */ + +// get the messages paginator the latest 30 messages +let messagesPaginator = await conversation.getMessages(30, 0, "backwards"); + +// get messages +const messages = messagesPaginator.items; diff --git a/conversations/listing-messages/listingMessages.ts b/conversations/listing-messages/listingMessages.ts new file mode 100644 index 000000000..3de879e42 --- /dev/null +++ b/conversations/listing-messages/listingMessages.ts @@ -0,0 +1,13 @@ +import {Message, Paginator} from "@twilio/conversations"; + +/* get the latest messages of the conversation. optional arguments: + pageSize | 30, + anchor | "end", + direction | "backwards" + */ + +// get the messages paginator with the latest 30 messages +let messagesPaginator: Paginator = await conversation.getMessages(30, 0, "backwards"); + +// get messages +const messages: Message[] = messagesPaginator.items; diff --git a/conversations/listing-participants/listingParticipants.js b/conversations/listing-participants/listingParticipants.js new file mode 100644 index 000000000..1b93c7160 --- /dev/null +++ b/conversations/listing-participants/listingParticipants.js @@ -0,0 +1,3 @@ +/* Get participants of the conversation */ + +let participants = await conversation.getParticipants(); diff --git a/conversations/listing-participants/listingParticipants.ts b/conversations/listing-participants/listingParticipants.ts new file mode 100644 index 000000000..49885f7f4 --- /dev/null +++ b/conversations/listing-participants/listingParticipants.ts @@ -0,0 +1,5 @@ +/* Get participants of the conversation */ + +import {Participant} from "@twilio/conversations"; + +let participants: Participant[] = await conversation.getParticipants(); diff --git a/conversations/media/media.js b/conversations/media/media.js new file mode 100644 index 000000000..a430c0af7 --- /dev/null +++ b/conversations/media/media.js @@ -0,0 +1,19 @@ +/* Check and update Media samples */ + +// Return all media attachments, except email body/history attachments, without temporary urls +const media = message.attachedMedia; + +// Return a (possibly empty) array of media matching a specific set of categories. Allowed category is so far only 'media' +const categorizedMedia = await message.getMediaByCategory(["media"]); + +const file = await fetch("https://v.fastcdn.co/u/ed1a9b17/52533501-0-logo.svg"); +const fileBlob = await file.blob(); + +// Send a media message +const sendMediaOptions = { + contentType: file.headers.get("Content-Type"), + filename: "twilio-logo.svg", + media: fileBlob +}; + +await conversation.prepareMessage().addMedia(sendMediaOptions); diff --git a/conversations/media/media.ts b/conversations/media/media.ts new file mode 100644 index 000000000..f1773e5b1 --- /dev/null +++ b/conversations/media/media.ts @@ -0,0 +1,20 @@ +/* Check and update Media samples */ +import {Media, SendMediaOptions} from "@twilio/conversations"; + +// Return all media attachments, except email body/history attachments, without temporary urls +const media: Media[] = message.attachedMedia; + +// Return a (possibly empty) array of media matching a specific set of categories. Allowed category is so far only 'media' +const categorizedMedia: Media[] = await message.getMediaByCategory(["media"]); + +const file = await fetch("https://v.fastcdn.co/u/ed1a9b17/52533501-0-logo.svg"); +const fileBlob = await file.blob(); + +// Send a media message +const sendMediaOptions: SendMediaOptions = { + contentType: file.headers.get("Content-Type"), + filename: "twilio-logo.svg", + media: fileBlob +}; + +await conversation.prepareMessage().addMedia(sendMediaOptions); diff --git a/conversations/message-builder/messageBuilder.js b/conversations/message-builder/messageBuilder.js new file mode 100644 index 000000000..95df8a7c1 --- /dev/null +++ b/conversations/message-builder/messageBuilder.js @@ -0,0 +1,10 @@ +/* Using MessageBuilder */ +// Message builder. Allows the message to be built and sent via method chaining. + +await testConversation.prepareMessage() + .setBody('Hello!') + .setAttributes({foo: 'bar'}) + .addMedia(media1) + .addMedia(media2) + .build() + .send(); diff --git a/conversations/message-builder/messageBuilder.ts b/conversations/message-builder/messageBuilder.ts new file mode 100644 index 000000000..95df8a7c1 --- /dev/null +++ b/conversations/message-builder/messageBuilder.ts @@ -0,0 +1,10 @@ +/* Using MessageBuilder */ +// Message builder. Allows the message to be built and sent via method chaining. + +await testConversation.prepareMessage() + .setBody('Hello!') + .setAttributes({foo: 'bar'}) + .addMedia(media1) + .addMedia(media2) + .build() + .send(); diff --git a/conversations/pagination/pagination.js b/conversations/pagination/pagination.js new file mode 100644 index 000000000..9d74ed35d --- /dev/null +++ b/conversations/pagination/pagination.js @@ -0,0 +1,42 @@ +/* Paginating through Conversation and Message lists */ + +// get the conversations paginator +let conversationsPaginator = await client.getSubscribedConversations(); + +// get conversations +const conversations = conversationsPaginator.items; + +// get the next page +if (conversationsPaginator.hasNextPage) { + conversationsPaginator = await conversationsPaginator.nextPage(); +} + +// get the previous page +if (conversationsPaginator.hasPrevPage) { + conversationsPaginator = await conversationsPaginator.prevPage(); +} + +/* get the latest messages of the conversation. optional arguments: + pageSize | 30, + anchor | "end", + direction | "backwards" + */ + +// get the messages paginator with latest 30 messages +let messagesPaginator = await conversation.getMessages(30, 0, "backwards"); + +// get messages amount of the conversation +const messagesCount = await conversation.getMessagesCount(); + +// get messages +const messages = messagesPaginator.items; + +// get the next page +if (messagesPaginator.hasNextPage) { + messagesPaginator = await messagesPaginator.nextPage(); +} + +// get the previous page +if (messagesPaginator.hasPrevPage) { + messagesPaginator = await messagesPaginator.prevPage(); +} diff --git a/conversations/pagination/pagination.ts b/conversations/pagination/pagination.ts new file mode 100644 index 000000000..d65bec06d --- /dev/null +++ b/conversations/pagination/pagination.ts @@ -0,0 +1,43 @@ +/* Paginating through Conversation and Message lists */ +import {Conversation, Message, Paginator} from "@twilio/conversations"; + +// get the conversations paginator +let conversationsPaginator: Paginator = await client.getSubscribedConversations(); + +// get conversations +const conversations: Conversation[] = conversationsPaginator.items; + +// get the next page +if (conversationsPaginator.hasNextPage) { + conversationsPaginator = await conversationsPaginator.nextPage(); +} + +// get the previous page +if (conversationsPaginator.hasPrevPage) { + conversationsPaginator = await conversationsPaginator.prevPage(); +} + +/* get the latest messages of the conversation. optional arguments: + pageSize | 30, + anchor | "end", + direction | "backwards" + */ + +// get the messages paginator with latest 30 messages +let messagesPaginator: Paginator = await conversation.getMessages(30, 0, "backwards"); + +// get messages amount of the conversation +const messagesCount: number = await conversation.getMessagesCount(); + +// get messages +const messages: Message[] = messagesPaginator.items; + +// get the next page +if (messagesPaginator.hasNextPage) { + messagesPaginator = await messagesPaginator.nextPage(); +} + +// get the previous page +if (messagesPaginator.hasPrevPage) { + messagesPaginator = await messagesPaginator.prevPage(); +} diff --git a/conversations/push-notifications/pushNotifications.js b/conversations/push-notifications/pushNotifications.js new file mode 100644 index 000000000..b91131d9c --- /dev/null +++ b/conversations/push-notifications/pushNotifications.js @@ -0,0 +1,20 @@ +/* Receiving and handling a push notification */ + +/* push registration. arguments: + @channelType - "apn" or "fcm" + @registrationId - can be retrieved from the firebase + */ +await client.setPushRegistrationId(channelType, registrationId); + +// remove push registration +await client.removePushRegistrations(channelType, registrationId); + +// handle push notification payload parsing and emit the Client.pushNotification event on this Client instance +await client.handlePushNotification(notificationPayload); + +client.on("pushNotification", (pushNotification) => { + // pushNotification was received by the client +}); + +// static method for push notification payload parsing +const pushNotification = Client.parsePushNotification(notificationPayload); diff --git a/conversations/push-notifications/pushNotifications.ts b/conversations/push-notifications/pushNotifications.ts new file mode 100644 index 000000000..eaa3cf45b --- /dev/null +++ b/conversations/push-notifications/pushNotifications.ts @@ -0,0 +1,21 @@ +/* Receiving and handling a push notification */ +import {Client, PushNotification} from "@twilio/conversations"; + +/* push registration. arguments: + @channelType - "apn" or "fcm" + @registrationId - a string, can be retrieved from the firebase + */ +await client.setPushRegistrationId(channelType, registrationId); + +// remove push registration +await client.removePushRegistrations(channelType, registrationId); + +// handle push notification payload parsing and emit the Client.pushNotification event on this Client instance +await client.handlePushNotification(notificationPayload); + +client.on("pushNotification", (pushNotification: PushNotification) => { + // pushNotification was received by the client +}); + +// static method for push notification payload parsing +const pushNotification: PushNotification = Client.parsePushNotification(notificationPayload); diff --git a/conversations/read-horizon/readHorizon.js b/conversations/read-horizon/readHorizon.js new file mode 100644 index 000000000..292bbe1c5 --- /dev/null +++ b/conversations/read-horizon/readHorizon.js @@ -0,0 +1,25 @@ +/* + Setting Read Horizon (all forms, like setAllRead, setNoneRead, advanceIndex, etc) + Retrieving/checking Read Horizon for rendering +*/ + +// get last read message index of the conversation +conversation.lastReadMessageIndex(); + +// get a message from conversation +const message = await conversation.getMessages().items[5]; + +// set last read message index of the conversation +await conversation.updateLastReadMessageIndex(message.index); + +// Mark all messages read +await conversation.setAllMessagesRead(); + +// Mark all messages unread +await conversation.setAllMessagesUnread(); + +// advance the conversation's last read message index to the current read horizon +await conversation.advanceLastReadMessageIndex(message.index); + +// get unread messages count for the user, that is, count of all the messages after message +await conversation.getUnreadMessagesCount(); diff --git a/conversations/read-horizon/readHorizon.ts b/conversations/read-horizon/readHorizon.ts new file mode 100644 index 000000000..6b82ffed1 --- /dev/null +++ b/conversations/read-horizon/readHorizon.ts @@ -0,0 +1,27 @@ +/* + Setting Read Horizon (all forms, like setAllRead, setNoneRead, advanceIndex, etc) + Retrieving/checking Read Horizon for rendering +*/ + +import {Message} from "@twilio/conversations"; + +// get last read message index of the conversation +conversation.lastReadMessageIndex(); + +// get a message from conversation +const message: Message = await conversation.getMessages().items[5]; + +// set last read message index of the conversation +await conversation.updateLastReadMessageIndex(message.index); + +// Mark all messages read +await conversation.setAllMessagesRead(); + +// Mark all messages unread +await conversation.setAllMessagesUnread(); + +// advance the conversation's last read message index to the current read horizon +await conversation.advanceLastReadMessageIndex(message.index); + +// get unread messages count for the user, that is, count of all the messages after message +await conversation.getUnreadMessagesCount(); diff --git a/conversations/send-multiple-media/sendMultipleMedia.js b/conversations/send-multiple-media/sendMultipleMedia.js new file mode 100644 index 000000000..2adb774dd --- /dev/null +++ b/conversations/send-multiple-media/sendMultipleMedia.js @@ -0,0 +1,23 @@ +/* Send multiple media */ + +const file = await fetch("https://v.fastcdn.co/u/ed1a9b17/52533501-0-logo.svg"); +const fileBlob = await file.blob(); + +const mediaFormData = new FormData(); +mediaFormData.set("twilio-logo", fileBlob, "twilio-logo.svg"); + +const sendMediaOptions = { + contentType: file.headers.get("Content-Type"), + filename: "twilio-logo.svg", + media: fileBlob +}; + +await testConversation.prepareMessage() + .setBody("Hello!") + // add multiple media + .addMedia(mediaFormData) + .addMedia(sendMediaOptions) + // ... + .addMedia(mediaN) + .build() + .send(); diff --git a/conversations/send-multiple-media/sendMultipleMedia.ts b/conversations/send-multiple-media/sendMultipleMedia.ts new file mode 100644 index 000000000..67fb35833 --- /dev/null +++ b/conversations/send-multiple-media/sendMultipleMedia.ts @@ -0,0 +1,25 @@ +/* Send multiple media */ + +import {SendMediaOptions} from "@twilio/conversations"; + +const file = await fetch("https://v.fastcdn.co/u/ed1a9b17/52533501-0-logo.svg"); +const fileBlob: Blob = await file.blob(); + +const mediaFormData = new FormData(); +mediaFormData.set("twilio-logo", fileBlob, "twilio-logo.svg"); + +const sendMediaOptions: SendMediaOptions = { + contentType: file.headers.get("Content-Type"), + filename: "twilio-logo.svg", + media: fileBlob +}; + +await testConversation.prepareMessage() + .setBody("Hello!") + // add multiple media + .addMedia(mediaFormData) + .addMedia(sendMediaOptions) + // ... + .addMedia(mediaN) + .build() + .send(); diff --git a/conversations/token/token.js b/conversations/token/token.js new file mode 100644 index 000000000..b104a7bce --- /dev/null +++ b/conversations/token/token.js @@ -0,0 +1,30 @@ +/* Handling token expiration/expiration warning events */ + +client.on("tokenAboutToExpire", (time) => { + // token is about to expire. get a new token + try { + const token = (await fetch("https://placekitten.com/getToken?username=username&password=password")).data(); + } catch { + return Error("Unable to get a token"); + } + + // update the client with new token + client = await client.updateToken(token); + + // use updated client +}); + +client.on("tokenExpired", () => { + // get a new token + try { + const token = (await fetch("https://placekitten.com/getToken?username=username&password=password")).data(); + } catch { + return Error("Unable to get a token"); + } + + // token expired. create a new client + client = new Client(token); +}); + +// update the token used by the client and re-register with the Conversations services +await client.updateToken("token"); diff --git a/conversations/token/token.ts b/conversations/token/token.ts new file mode 100644 index 000000000..d25806f5f --- /dev/null +++ b/conversations/token/token.ts @@ -0,0 +1,32 @@ +/* Handling token expiration/expiration warning events */ + +import {Client} from "@twilio/conversations"; + +client.on("tokenAboutToExpire", async (time: number) => { + // token is about to expire. get a new token + try { + const token: string = (await fetch("http://placekitten.com/getToken?username=username&password=password")).data(); + } catch { + return Error("Unable to get a token"); + } + + // update the client with new token + client = await client.updateToken(token); + + // use updated client +}); + +client.on("tokenExpired", async () => { + // get a new token + try { + const token: string = (await fetch("http://placekitten.com/getToken?username=username&password=password")).data(); + } catch { + return Error("Unable to get a token"); + } + + // token expired. create a new client + client = new Client(token); +}); + +// update the token used by the client and re-register with the Conversations services +await client.updateToken("token"); diff --git a/conversations/typing-indicator/typingIndicator.js b/conversations/typing-indicator/typingIndicator.js new file mode 100644 index 000000000..70dfd71c4 --- /dev/null +++ b/conversations/typing-indicator/typingIndicator.js @@ -0,0 +1,14 @@ +/* Typing indicator */ + +// the user is typing +messageInput.on("change", async () => { + await conversation.typing(); +}); + +conversation.on("typingStarted", (participant) => { + // getting a participant that started typing +}); + +conversation.on("typingEnded", (participant) => { + // getting a participant that finished typing +}); diff --git a/conversations/typing-indicator/typingIndicator.ts b/conversations/typing-indicator/typingIndicator.ts new file mode 100644 index 000000000..a34c98691 --- /dev/null +++ b/conversations/typing-indicator/typingIndicator.ts @@ -0,0 +1,15 @@ +/* Typing indicator */ +import {Participant} from "@twilio/conversations"; + +// the user is typing +messageInput.on("change", async () => { + await conversation.typing(); +}); + +conversation.on("typingStarted", (participant: Participant) => { + // getting a participant that started typing +}); + +conversation.on("typingEnded", (participant: Participant) => { + // getting a participant that finished typing +}); diff --git a/conversations/updating/updating.js b/conversations/updating/updating.js new file mode 100644 index 000000000..cbdb67f8d --- /dev/null +++ b/conversations/updating/updating.js @@ -0,0 +1,17 @@ +/* Updating Conversations/Messages/Participants */ + +/* Conversations */ + +await conversation.updateAttributes({}); +await conversation.updateFriendlyName("foo"); +await conversation.updateLastReadMessageIndex(0); +await conversation.updateUniqueName("foo"); + +/* Messages */ + +await message.updateAttributes([1, {foo: "bar"}]); +await message.updateBody("bar"); + +/* Participants */ + +await participant.updateAttributes({foo: 8}); diff --git a/conversations/updating/updating.ts b/conversations/updating/updating.ts new file mode 100644 index 000000000..cbdb67f8d --- /dev/null +++ b/conversations/updating/updating.ts @@ -0,0 +1,17 @@ +/* Updating Conversations/Messages/Participants */ + +/* Conversations */ + +await conversation.updateAttributes({}); +await conversation.updateFriendlyName("foo"); +await conversation.updateLastReadMessageIndex(0); +await conversation.updateUniqueName("foo"); + +/* Messages */ + +await message.updateAttributes([1, {foo: "bar"}]); +await message.updateBody("bar"); + +/* Participants */ + +await participant.updateAttributes({foo: 8}); diff --git a/conversations/user-reachability/userReachability.js b/conversations/user-reachability/userReachability.js new file mode 100644 index 000000000..806b7275e --- /dev/null +++ b/conversations/user-reachability/userReachability.js @@ -0,0 +1,32 @@ +/* Checking/listening to reachability */ + +// check if reachability function is enabled +if (!client.reachabilityEnabled) { + // reachability function is disabled for the client + return; +} + +// listen to user reachability status updates +client.on("userUpdated", ({ user, updateReasons}) => { + if (updateReasons.includes("reachabilityOnline")) { + // user reachability status was updated + } + + if (updateReasons.includes("reachabilityNotifiable")) { + // user notifications status was updated + } +}) + +const participants = await conversation.getParticipants(); + +participants.forEach(async (participant) => { + const user = await participant.getUser(); + + if (user.isOnline) { + // conversation participant is online + } + + if (user.isNotifiable) { + // user has push notifications active + } +}); diff --git a/conversations/user-reachability/userReachability.ts b/conversations/user-reachability/userReachability.ts new file mode 100644 index 000000000..64ab590af --- /dev/null +++ b/conversations/user-reachability/userReachability.ts @@ -0,0 +1,36 @@ +/* Checking/listening to reachability */ +import {Participant, User, UserUpdateReason} from "@twilio/conversations"; + +// check if reachability function is enabled +if (!client.reachabilityEnabled) { + // reachability function is disabled for the client + return; +} + +// listen to user reachability status updates +client.on("userUpdated", ({ user, updateReasons}: { + user: User, + updateReasons: UserUpdateReason[] +}) => { + if (updateReasons.includes("reachabilityOnline")) { + // user reachability status was updated + } + + if (updateReasons.includes("reachabilityNotifiable")) { + // user notifications status was updated + } +}) + +const participants: Participant[] = await conversation.getParticipants(); + +participants.forEach(async (participant) => { + const user: User = await participant.getUser(); + + if (user.isOnline) { + // conversation participant is online + } + + if (user.isNotifiable) { + // user has push notifications active + } +});