feat: tansfer calls with aasterisk

This commit is contained in:
Sabiha Khan 2026-02-23 12:09:45 +05:30
parent 7aef9c6db5
commit 30eebfe811
10 changed files with 494 additions and 86 deletions

4
ui/package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "ui",
"version": "1.13.0",
"version": "1.14.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ui",
"version": "1.13.0",
"version": "1.14.0",
"dependencies": {
"@dagrejs/dagre": "^1.1.4",
"@hey-api/client-fetch": "^0.10.0",

View file

@ -5,6 +5,7 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { Textarea } from "@/components/ui/textarea";
import { useState, useEffect } from "react";
import { type EndCallMessageType } from "../../config";
@ -37,20 +38,46 @@ export function TransferCallToolConfig({
timeout,
onTimeoutChange,
}: TransferCallToolConfigProps) {
// Basic E.164 validation pattern
const [sipMode, setSipMode] = useState(() => /^(PJSIP|SIP)\//i.test(destination));
// Validation patterns
const isValidPhoneNumber = (phone: string): boolean => {
const e164Pattern = /^\+[1-9]\d{1,14}$/;
return e164Pattern.test(phone);
};
const phoneNumberError = destination && !isValidPhoneNumber(destination);
const isValidSipEndpoint = (endpoint: string): boolean => {
const sipPattern = /^(PJSIP|SIP)\/[\w\-\.@]+$/i;
return sipPattern.test(endpoint);
};
const getValidationError = (): string | null => {
if (!destination) return null;
if (sipMode) {
return isValidSipEndpoint(destination)
? null
: "Please enter a valid SIP endpoint (e.g., PJSIP/1234 or SIP/extension@domain.com)";
} else {
return isValidPhoneNumber(destination)
? null
: "Please enter a valid phone number in E.164 format (e.g., +1234567890)";
}
};
const destinationError = getValidationError();
const handleSipModeToggle = () => {
setSipMode(!sipMode);
onDestinationChange(""); // Clear destination when switching modes
};
return (
<Card>
<CardHeader>
<CardTitle>Transfer Call Configuration</CardTitle>
<CardDescription>
Configure call transfer settings (Twilio only)
Configure call transfer settings. Supports phone numbers (Twilio) and SIP endpoints (Asterisk ARI).
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
@ -80,21 +107,31 @@ export function TransferCallToolConfig({
</div>
<div className="grid gap-2 pt-4 border-t">
<Label>Destination Phone Number</Label>
<Label>Transfer Destination</Label>
<Label className="text-xs text-muted-foreground">
Phone number to transfer the call to (E.164 format with country code)
{sipMode
? "SIP endpoint to transfer the call to (e.g., PJSIP/1234 or SIP/extension@domain.com)"
: "Phone number to transfer the call to (E.164 format with country code)"
}
</Label>
<Input
value={destination}
onChange={(e) => onDestinationChange(e.target.value)}
placeholder="+1234567890"
className={phoneNumberError ? "border-red-500 focus:border-red-500" : ""}
placeholder={sipMode ? "PJSIP/1234 or SIP/extension@domain.com" : "+1234567890"}
className={destinationError ? "border-red-500 focus:border-red-500" : ""}
/>
{phoneNumberError && (
{destinationError && (
<Label className="text-xs text-red-500">
Please enter a valid phone number in E.164 format (e.g., +1234567890)
{destinationError}
</Label>
)}
<button
type="button"
className="text-xs text-muted-foreground hover:text-foreground underline w-fit"
onClick={handleSipModeToggle}
>
{sipMode ? "Use phone number instead" : "Use SIP endpoint instead"}
</button>
</div>
<div className="grid gap-4 pt-4 border-t">

View file

@ -198,10 +198,14 @@ export default function ToolDetailPage() {
// Validation based on tool type
if (tool.category === "transfer_call") {
// Validate destination phone number for Transfer Call tools
// Validate destination for Transfer Call tools (supports both E.164 and SIP endpoints)
const e164Pattern = /^\+[1-9]\d{1,14}$/;
if (!transferDestination || !e164Pattern.test(transferDestination)) {
setError("Please enter a valid phone number in E.164 format (e.g., +1234567890)");
const sipPattern = /^(PJSIP|SIP)\/[\w\-\.@]+$/i;
const isValidE164 = e164Pattern.test(transferDestination);
const isValidSip = sipPattern.test(transferDestination);
if (!transferDestination || (!isValidE164 && !isValidSip)) {
setError("Please enter a valid phone number (E.164 format) or SIP endpoint (e.g., PJSIP/1234)");
return;
}
} else if (tool.category !== "end_call") {