Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3e98956
WIP
stephenhand Jun 11, 2026
6e5eea1
WIP
stephenhand Jun 11, 2026
99ff99f
WIP post survey calls
stephenhand Jun 15, 2026
8444c99
Fix post studio flow for voice logic and add log
stephenhand Jun 15, 2026
a701f9d
Add logs to post studio flow for voice logic
stephenhand Jun 15, 2026
d4ee435
Add logs to post studio flow for voice logic
stephenhand Jun 15, 2026
121a5bc
Update conference monitor to not end conference on exit if post flow …
stephenhand Jun 15, 2026
6b45516
Extra logging for post studio flow setup
stephenhand Jun 16, 2026
1ddb1b3
Complete conference on post survey flow
stephenhand Jun 16, 2026
30e411d
Try redirecting using twilml
stephenhand Jun 16, 2026
1069951
Try redirecting parent call using twilml
stephenhand Jun 16, 2026
9b02e70
Fix log
stephenhand Jun 16, 2026
85ce796
Try redirecting from reservation
stephenhand Jun 16, 2026
78bd0c1
Try redirecting using a TwilML bin
stephenhand Jun 16, 2026
4dbac66
Try putting the participant on hold before removing from the conference
stephenhand Jun 17, 2026
6a3ed8e
Try putting the participant on hold before removing from the conferen…
stephenhand Jun 17, 2026
cde3a65
Try putting the participant on hold before removing from the conferen…
stephenhand Jun 17, 2026
e1b620f
Remove participant AFTER setting redirect
stephenhand Jun 17, 2026
ba6ed35
Remove participant AFTER setting redirect
stephenhand Jun 17, 2026
c0a420b
Use twilml URL
stephenhand Jun 17, 2026
a5ba182
Dial studio flow
stephenhand Jun 18, 2026
9bcfc5e
Dial studio flow
stephenhand Jun 18, 2026
97134e2
Add contact ID to dial
stephenhand Jun 18, 2026
2bc40a5
Add contact ID to inline twiml
stephenhand Jun 18, 2026
cb633c4
Reorganised post survey code a bit. Added mechanism to stash contact …
stephenhand Jun 18, 2026
62e86c6
Changed sync doc creation from remove-then-create to upsert
stephenhand Jun 19, 2026
64cb577
Tidy up logs, remove participant from conference on error
stephenhand Jun 19, 2026
785cbad
savePostSurvey logging
stephenhand Jun 19, 2026
f74b93b
Remove slashes and pluses from unique doc names
stephenhand Jun 19, 2026
40d8e80
Fix twilio mock in taskrouterEventHandler test to include twiml.Voice…
Copilot Jun 19, 2026
ed5e1e2
Fix setUpConferenceActions test: add postStudioFlows to mock and upda…
Copilot Jun 19, 2026
5348441
Linter
stephenhand Jun 19, 2026
9057132
Pass phone number as post studio flow identifier
stephenhand Jun 19, 2026
3045993
Merge branch 'CHI-3716-call_post_survey' into CHI-3915-sms_post_call_…
stephenhand Jun 19, 2026
422a269
WIP - voice post studio flow kicked off from REST API (no call), and …
stephenhand Jun 19, 2026
fdaef04
Logging
stephenhand Jun 23, 2026
cd6b631
Merge branch 'master' into CHI-3915-sms_post_call_survey_poc
stephenhand Jun 23, 2026
162601b
Change from number in post call text surveys
stephenhand Jun 23, 2026
678b20d
Fix merge
stephenhand Jun 23, 2026
c4e218d
Revert to using same number for post conversation
stephenhand Jun 24, 2026
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
1 change: 0 additions & 1 deletion aselo-webchat-react-app/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
-->
<link rel="shortcut icon" href="https://media.twiliocdn.com/sdk/js/webchat-v3/assets/favicon.ico">
<title>Twilio Webchat React App</title>
<link rel="stylesheet" href="./app.css">
<script defer src="./app.js"></script>
</head>
Comment on lines 28 to 31

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
getChatServiceSid,
getHelplineCode,
getSurveyWorkflowSid,
getTwilioWorkspaceSid,
getWorkspaceSid,
} from '@tech-matters/twilio-configuration';

export const handleCaptureChannelWithBot: AccountScopedHandler = async (
Expand Down Expand Up @@ -61,7 +61,7 @@ export const handleCaptureChannelWithBot: AccountScopedHandler = async (
const chatServiceSid = await getChatServiceSid(accountSid);
const helplineCode = await getHelplineCode(accountSid);
const surveyWorkflowSid = await getSurveyWorkflowSid(accountSid);
const twilioWorkspaceSid = await getTwilioWorkspaceSid(accountSid);
const twilioWorkspaceSid = await getWorkspaceSid(accountSid);

const result = await handleChannelCapture(twilioClient, {
accountSid,
Expand Down
120 changes: 12 additions & 108 deletions lambdas/account-scoped/src/channelCapture/channelCaptureHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,11 @@ import { ConversationInstance } from 'twilio/lib/rest/conversations/v1/conversat
import type { TaskInstance } from 'twilio/lib/rest/taskrouter/v1/workspace/task';
import type { MemberInstance } from 'twilio/lib/rest/ipMessaging/v2/service/channel/member';
import { LexClient, LexMemory } from './lexClient';
import { PostSurveyData, buildDataObject } from './hrmDataManipulation';
import { buildSurveyInsightsData } from './insightsService';
import { isErr, newErr, newOk, Result } from '../Result';
import { Twilio } from 'twilio';
import { postToInternalHrmEndpoint } from '../hrm/internalHrmRequest';
import { ROUTE_PREFIX } from '../router';
import { AccountSID } from '@tech-matters/twilio-types';
import { getCurrentDefinitionVersion } from '../hrm/formDefinitionsCache';
import { LegacyOneToManyConfigSpec } from '@tech-matters/hrm-form-definitions';
import { savePostSurvey } from '../hrm/savePostSurvey';

const triggerTypes = ['withUserMessage', 'withNextMessage'] as const;
export type TriggerTypes = (typeof triggerTypes)[number];
Expand Down Expand Up @@ -613,105 +609,6 @@ const createStudioFlowTrigger = async (
});
};

type PostSurveyBody = {
contactTaskId: string;
taskId: string;
data: PostSurveyData;
};

const saveSurveyInInsights = async (
postSurveyConfigJson: LegacyOneToManyConfigSpec[],
memory: LexMemory,
controlTask: TaskInstance,
controlTaskAttributes: any,
) => {
const finalAttributes = buildSurveyInsightsData(
postSurveyConfigJson,
controlTaskAttributes,
memory,
);

await controlTask.update({ attributes: JSON.stringify(finalAttributes) });
};

const saveSurveyInHRM = async ({
accountSid,
controlTask,
controlTaskAttributes,
hrmApiVersion,
memory,
postSurveyConfigSpecs,
}: {
postSurveyConfigSpecs: LegacyOneToManyConfigSpec[];
memory: LexMemory;
controlTask: TaskInstance;
controlTaskAttributes: any;
accountSid: AccountSID;
hrmApiVersion: string;
}) => {
const data = buildDataObject(postSurveyConfigSpecs, memory);

const body: PostSurveyBody = {
contactTaskId: controlTaskAttributes.contactTaskId,
taskId: controlTask.sid,
data,
};

await postToInternalHrmEndpoint(accountSid, hrmApiVersion, 'postSurveys', body);
};

const handlePostSurveyComplete = async ({
accountSid,
controlTask,
memory,
twilioClient,
}: {
accountSid: AccountSID;
twilioClient: Twilio;
memory: LexMemory;
controlTask: TaskInstance;
}) => {
const serviceConfig = await twilioClient.flexApi.v1.configuration.get().fetch();

const { hrm_api_version: hrmApiVersion } = serviceConfig.attributes;
const definition = await getCurrentDefinitionVersion({ accountSid });
const postSurveyConfigSpecs = definition?.insights?.postSurveySpecs;

try {
if (!postSurveyConfigSpecs?.length) {
const errorMEssage = `No defined or invalid postSurveyConfigJson found for account ${accountSid}.`;
throw new Error(errorMEssage);
}

const controlTaskAttributes = JSON.parse(controlTask.attributes);

// parallel execution to save survey collected data in insights and hrm
await Promise.all([
saveSurveyInInsights(
postSurveyConfigSpecs,
memory,
controlTask,
controlTaskAttributes,
),
saveSurveyInHRM({
postSurveyConfigSpecs,
memory,
controlTask,
controlTaskAttributes,
accountSid,
hrmApiVersion,
}),
]);
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
console.error(`Error accessing to the post survey form definitions: ${message}`);
} finally {
// As survey tasks will never be assigned to a worker, they'll be kept in pending state. A pending can't transition to completed state, so we cancel them here to raise a task.canceled taskrouter event (see functions/taskrouterListeners/janitorListener.ts)
// This needs to be the last step so the new task attributes from saveSurveyInInsights make it to insights
await controlTask.update({ assignmentStatus: 'canceled' });
}
};

export const handleChannelRelease = async ({
accountSid,
capturedChannelAttributes,
Expand All @@ -729,10 +626,11 @@ export const handleChannelRelease = async ({
}) => {
try {
// get the control task
const controlTask = await twilioClient.taskrouter.v1
const controlTaskContext = twilioClient.taskrouter.v1
.workspaces(twilioWorkspaceSid)
.tasks(capturedChannelAttributes.controlTaskSid)
.fetch();
.tasks(capturedChannelAttributes.controlTaskSid);
// get the control task
const controlTask = await controlTaskContext.fetch();

if (capturedChannelAttributes.releaseType === 'triggerStudioFlow') {
await createStudioFlowTrigger(
Expand All @@ -743,7 +641,13 @@ export const handleChannelRelease = async ({
}

if (capturedChannelAttributes.releaseType === 'postSurveyComplete') {
await handlePostSurveyComplete({ memory, controlTask, accountSid, twilioClient });
await savePostSurvey({
postSurveyAnswers: memory,
controlTask,
accountSid,
twilioClient,
});
await controlTaskContext.update({ assignmentStatus: 'canceled' });
}

return newOk({});
Expand Down
61 changes: 0 additions & 61 deletions lambdas/account-scoped/src/channelCapture/hrmDataManipulation.ts

This file was deleted.

Loading
Loading