feat: add in-browser dial pad with Twilio Voice SDK

- New DialPad component on Patient Connection page: clickable keypad,
  call/hangup/mute buttons, duration timer, keyboard input support
- Backend: POST /api/twilio/voice-token issues Access Token for browser
  Device; POST /api/twilio/webhook/voice-browser is the TwiML webhook
  Twilio calls to bridge the browser to the patient's phone
- TwiML App SID field added to Twilio Settings (stored in templates JSON)
- README: one-time Twilio Console setup instructions for the dial pad

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ff
2026-06-02 22:24:53 -04:00
co-authored by Claude Sonnet 4.6
parent be90966f6e
commit ddcc49b72c
9 changed files with 409 additions and 4 deletions
+11 -2
View File
@@ -5,6 +5,7 @@ export type TwilioSettingsData = {
authToken: string;
phoneNumber: string;
greetingMessage?: string | null;
twimlAppSid?: string | null;
};
export type CommunicationCreateData = {
@@ -24,10 +25,18 @@ export const twilioStorage = {
},
async upsertTwilioSettings(userId: number, data: TwilioSettingsData) {
const { twimlAppSid, ...rest } = data;
const existing = await db.twilioSettings.findUnique({ where: { userId } });
const existingTemplates = (existing?.templates as Record<string, string>) || {};
const templates: Record<string, string> = { ...existingTemplates };
if (twimlAppSid !== undefined) {
if (twimlAppSid) templates["_twiml_app_sid"] = twimlAppSid;
else delete templates["_twiml_app_sid"];
}
return db.twilioSettings.upsert({
where: { userId },
update: data,
create: { userId, ...data },
update: { ...rest, templates },
create: { userId, ...rest, templates },
});
},