Skip to content
Open
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
12 changes: 6 additions & 6 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ACCOUNT_SID='Your account SID'
AUTH_TOKEN='The Auth token'
WORKSPACE_SID='TaskRouter Workspace'
WORKFLOW_SID='TaskRouter Workflow'
INTERACTION_URL='https://flex-api.twilio.com/v1/Interactions'
APP_URL='The application url to get webhooks e.g. https://98a3-2601-648-8682-d360-7d1d-bb5c-28df-400f.ngrok.io'
FLEX_ACCOUNT_SID='Your account SID'
FLEX_AUTH_TOKEN='The Auth token'
FLEX_WORKSPACE_SID='TaskRouter Workspace'
FLEX_WORKFLOW_SID='TaskRouter Workflow'
FLEX_INTERACTION_URL='https://flex-api.twilio.com/v1/Interactions'
FLEX_APP_URL='The application url to get webhooks e.g. https://98a3-2601-648-8682-d360-7d1d-bb5c-28df-400f.ngrok.io'
165 changes: 164 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,166 @@
<a href="https://www.twilio.com">
<img src="https://static0.twilio.com/marketing/bundles/marketing/img/logos/wordmark-red.svg" alt="Twilio" width="250" />
</a>

# Park and Transfer Flex Plugin

The Park and Transfer Flex plugin facilitates pausing and transferring of [Flex Conversations](https://www.twilio.com/docs/flex/conversations) tasks.

## Set up

Please see the Flex Conversations [Prerequisites](https://www.twilio.com/docs/flex/admin-guide/setup/conversations/prerequisites) page to prepare your Flex account for testing.

### Twilio Account Settings

Before we begin, we need to collect
all the environment variables we need to run the application:
- **FLEX_APP_ACCOUNT_SID** - Your primary Twilio account identifier or username - find this [in the Console](https://www.twilio.com/console)
- **FLEX_APP_AUTH_TOKEN** - Your Twilio account auth token or password - find this [in the Console](https://www.twilio.com/console)
- **FLEX_APP_WORKSPACE_SID** - Your Twilio TaskRouter workspace. Named "Flex Task Assignment" by default.
- **FLEX_APP_WORKFLOW_SID** - Your Twilio TaskRouter Workflow that you want to use for task pauses and transfers.
- **FLEX_APP_INTERACTION_URL** - The Interactions API Endpoint. Set this to `https://flex-api.twilio.com/v1/Interactions`.
- **FLEX_APP_URL** - Your publicly accessible ngrok domain (in https) if you do not have a public server. Note that you will need to create an ngrok account and add your authtoken. See the [ngrok setup guide](https://dashboard.ngrok.com/get-started/setup) for more details. The app in this plugin uses port 9000 by default. To start, run `ngrok http 9000`.

In the root directory of your repository clone, copy `.env.template` to `.env.` Update the file with your Twilio account settings.

Copy .env.template to .env to the root of the project in the root of the project
Update the values in the .env (If you dont have a public server, use ngrok, port 9000 by default, and use the fqdn as the APP_URL in the .env file)
Start node /bin/www


### Test the plugin

After the above requirements have been met, do the following:
1. Change into the server directory.
`cd server`
2. Run `npm install` to install the package dependencies.
3. Run `npm start`.
4. In a different tab, run `twilio flex:plugins:start` in the root directory of the repo. This should start up your Flex application on localhost.
5. To test, send an SMS or a WhatsApp message to your Twilio Flex number with a Conversations address. You should see the Pause and Transfer buttons in the Flex Task Canvas.

```
git clone git@github.com:twilio-labs/plugin-queued-callbacks-and-voicemail.git
```

2. Change into the `public` subdirectory of the repo and run the following:

```
cd plugin-queued-callbacks-and-voicemail/public && mv appConfig.example.js appConfig.js
```

3. Install dependencies

```bash
npm install
```

4. [Deploy your Twilio Functions and Assets](#twilio-serverless-deployment)

5. Run the application

```bash
twilio flex:plugins:start
```

See [Twilio Account Settings](#twilio-account-settings) to locate the necessary environment variables.

7. Run the application

```bash
npm start
```

Alternatively, you can use this command to start the server in development mode. It will reload whenever you change any files.

```bash
npm run dev
```

8. Navigate to [http://localhost:3000](http://localhost:3000)

That's it!

#### Pre-deployment Steps

1. From the root directory of your copy of the source code, change into `serverless` and rename `.env.example` to `.env`.

```
cd serverless && mv .env.example .env
```

2. Open `.env` with your text editor and modify TWILIO_WORKSPACE_SID with your Flex Task Assignment SID.

```
TWILIO_WORKSPACE_SID=WSxxxxxxxxxxxxxxxxxxxxxx`
```

3. To deploy your Callback and Voicemail functions and assets, run the following:

```
$ twilio serverless:deploy --assets

## Example Output
Deploying functions & assets to the Twilio Runtime
Env Variables
⠇ Creating 4 Functions
✔ Serverless project successfully deployed

Deployment Details
Domain: plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io
Service:
plugin-queued-callbacks-voicemail-functions
Functions:
https://plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io/inqueue-callback
https://plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io/inqueue-utils
https://plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io/queue-menu
https://plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io/inqueue-voicemail

Assets:
https://plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io/assets/alertTone.mp3
https://plugin-queued-callbacks-voicemail-functions-xxxx-dev.twil.io/assets/guitar_music.mp3
```

_Note:_ Copy and save the domain returned when you deploy a function. You will need it in the next step. If you forget to copy the domain, you can also find it by navigating to [Functions > API](https://www.twilio.com/console/functions/api) in the Twilio Console.

> Debugging Tip: Pass the -l or logging flag to review deployment logs. For example, you can pass `-l debug` to turn on debugging logs.

### Deploy your Flex Plugin

Once you have deployed the function, it is time to deploy the plugin to your Flex instance.

Run the following commands in the plugin root directory. We will leverage the Twilio CLI to build and deploy the Plugin.

1. Rename `.env.example` to `.env`.
2. Open `.env` with your text editor and modify the `REACT_APP_SERVICE_BASE_URL` property to the Domain name you copied in the previous step. Make sure to prefix it with "https://".

```
plugin-queued-callbacks-and-voicemail $ mv .env.example .env

# .env
REACT_APP_SERVICE_BASE_URL=https://plugin-queued-callbacks-voicemail-functions-4135-dev.twil.io
```

3. When you are ready to deploy the plugin, run the following in a command shell:

```
plugin-queued-callbacks-and-voicemail $ twilio flex:plugins:deploy --major --changelog "Updating to use the latest Twilio CLI Flex plugin" --description "Queued callbacks and voicemail"
```

4. To enable the plugin on your contact center, follow the suggested next step on the deployment confirmation. To enable it via the Flex UI, see the [Plugins Dashboard documentation](https://www.twilio.com/docs/flex/developer/plugins/dashboard#stage-plugin-changes).


Update the values in the .env (If you dont have a public server, use ngrok, port 9000 by default, and use the fqdn as the APP_URL in the .env file)
Start node /bin/www
Start the server - see README in server director
Update the server URL in actions.js
start the plugin
start the plugin

## License

[MIT](http://www.opensource.org/licenses/mit-license.html)

## Disclaimer

No warranty expressed or implied. Software is as is.

[twilio]: https://www.twilio.com
26 changes: 13 additions & 13 deletions server/routes/interactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ const axios = require('axios');
const FormData = require('form-data');
const createError = require('http-errors');
const express = require('express');
const client = require('twilio')(process.env.ACCOUNT_SID, process.env.AUTH_TOKEN);
const client = require('twilio')(process.env.FLEX_APP_ACCOUNT_SID, process.env.FLEX_APP_AUTH_TOKEN);

const router = express.Router();
const { WORKSPACE_SID, WORKFLOW_SID, INTERACTION_URL, APP_URL } = process.env;
const REINVITE_ENDPOINT = `${APP_URL}/interactions/reinvite`;
const { FLEX_APP_WORKSPACE_SID, FLEX_APP_WORKFLOW_SID, FLEX_APP_INTERACTION_URL, FLEX_APP_URL } = process.env;
const REINVITE_ENDPOINT = `${FLEX_APP_URL}/interactions/reinvite`;

async function closeParticipant(interactionSid, channelSid, participantSid) {
const closeParticipantUrl = `${INTERACTION_URL}/${interactionSid}/Channels/${channelSid}/Participants/${participantSid}`;
const closeParticipantUrl = `${FLEX_APP_INTERACTION_URL}/${interactionSid}/Channels/${channelSid}/Participants/${participantSid}`;
const formData = new FormData();
formData.append('Status', 'closed');

Expand All @@ -20,23 +20,23 @@ async function closeParticipant(interactionSid, channelSid, participantSid) {
data: formData,
headers: formData.getHeaders(),
auth: {
username: process.env.ACCOUNT_SID,
password: process.env.AUTH_TOKEN,
username: process.env.FLEX_APP_ACCOUNT_SID,
password: process.env.FLEX_APP_AUTH_TOKEN,
},
});
}

async function inviteParticipant(interactionSid, channelSid, workflowSid, taskChannelUniqueName, taskAttributes) {
const inviteUrl = `${INTERACTION_URL}/${interactionSid}/Channels/${channelSid}/Invites`;
const inviteUrl = `${FLEX_APP_INTERACTION_URL}/${interactionSid}/Channels/${channelSid}/Invites`;

/*
* TODO fix workspace sid
* TOD fix workflow sid. We now use the same one the original came on. Do we want to have this as a setting or dynamic?
*/
const routingBody = `{"type":"TaskRouter",
"properties":{
"workspace_sid":"${WORKSPACE_SID}",
"worklow_sid":"${workflowSid}",
"workspace_sid":"${FLEX_APP_WORKSPACE_SID}",
"workflow_sid":"${workflowSid}",
"task_channel_unique_name": "${taskChannelUniqueName}",
"attributes": ${JSON.stringify(taskAttributes)} } }`;

Expand All @@ -50,14 +50,14 @@ async function inviteParticipant(interactionSid, channelSid, workflowSid, taskCh
data: formData,
headers: formData.getHeaders(),
auth: {
username: process.env.ACCOUNT_SID,
password: process.env.AUTH_TOKEN,
username: process.env.FLEX_APP_ACCOUNT_SID,
password: process.env.FLEX_APP_AUTH_TOKEN,
},
});
}

async function closeParticipantAndtransfer(interactionSid, channelSid, participantSid, targetSid, taskChannelUniqueName, taskAttributes) {
const closeParticipantUrl = `${INTERACTION_URL}/${interactionSid}/Channels/${channelSid}/Participants/${participantSid}`
const closeParticipantUrl = `${FLEX_APP_INTERACTION_URL}/${interactionSid}/Channels/${channelSid}/Participants/${participantSid}`
const formData = new FormData();
formData.append('Status', 'closed');

Expand All @@ -71,7 +71,7 @@ async function closeParticipantAndtransfer(interactionSid, channelSid, participa
console.log(`Participant closed successfully`);

try {
const inviteResponse = await inviteParticipant(interactionSid, channelSid, WORKFLOW_SID, taskChannelUniqueName, taskAttributes);
const inviteResponse = await inviteParticipant(interactionSid, channelSid, FLEX_APP_WORKFLOW_SID, taskChannelUniqueName, taskAttributes);
console.log(`Participant invited successfully`);
} catch (err) {
console.log(`Could not invite participant :( ${err}`)
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/actions.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Actions, TaskHelper, Manager, Notifications, StateHelper } from '@twilio/flex-ui';
import fetch from 'node-fetch';

const SERVER_URL = 'https://98a3-2601-648-8682-d360-7d1d-bb5c-28df-400f.ngrok.io';
const SERVER_URL = 'http://49ef8b56f039.ngrok.io';

// Once you publish the chat transfer function, place the returned domain in your version of the plugin.

Expand Down