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:
@@ -1203,4 +1203,26 @@ router.post("/webhook/voice-recording", async (req: Request, res: Response): Pro
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/twilio/webhook/voice-browser
|
||||
// Called by Twilio when a browser Device (Voice SDK) places an outbound call.
|
||||
// Looks up the office's Twilio phone number by AccountSid and dials the patient.
|
||||
router.post("/webhook/voice-browser", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const { To, AccountSid } = req.body as { To?: string; AccountSid?: string };
|
||||
if (!To || !AccountSid) {
|
||||
res.set("Content-Type", "text/xml");
|
||||
return res.send("<Response><Say>Missing call parameters.</Say></Response>");
|
||||
}
|
||||
const settings = await db.twilioSettings.findFirst({ where: { accountSid: AccountSid } });
|
||||
const callerId = settings?.phoneNumber || "";
|
||||
res.set("Content-Type", "text/xml");
|
||||
return res.send(
|
||||
`<Response><Dial callerId="${escapeXml(callerId)}"><Number>${escapeXml(To)}</Number></Dial></Response>`
|
||||
);
|
||||
} catch {
|
||||
res.set("Content-Type", "text/xml");
|
||||
return res.send("<Response><Say>An error occurred. Please try again.</Say></Response>");
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user