fix: added UI when there is incoming call and also for outgoing call
This commit is contained in:
parent
9b41aea198
commit
3868f5dbe5
@ -58,48 +58,3 @@ def twilio_incoming_call_handler(**kwargs):
|
|||||||
|
|
||||||
resp = IncomingCall(args.From, args.To).process()
|
resp = IncomingCall(args.From, args.To).process()
|
||||||
return Response(resp.to_xml(), mimetype='text/xml')
|
return Response(resp.to_xml(), mimetype='text/xml')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# @frappe.whitelist(allow_guest=True)
|
|
||||||
# def twilio_incoming_call_handler(**kwargs):
|
|
||||||
# args = frappe._dict(kwargs)
|
|
||||||
# resp = VoiceResponse()
|
|
||||||
|
|
||||||
# resp.say("Thank you for calling! Have a great day.", voice='Polly.Amy')
|
|
||||||
|
|
||||||
# todo = frappe.get_doc({
|
|
||||||
# "doctype": "ToDo",
|
|
||||||
# "description": "Call from {0} to {1} is {2}".format(args.From, args.To, args.CallStatus),
|
|
||||||
# })
|
|
||||||
# todo.insert(ignore_permissions=True)
|
|
||||||
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def make_call(to, from_='+13134748669'):
|
|
||||||
application_sid = 'APa7a85c103b7477c8eb25e9a8aafae055'
|
|
||||||
account_sid = 'AC1a65d630772fbdb3a9a977c46aacef61'
|
|
||||||
auth_token = '1eb29b621c6a60f4afdde18160bc1e2d'
|
|
||||||
client = Client(account_sid, auth_token)
|
|
||||||
|
|
||||||
call = client.calls.create(
|
|
||||||
url='http://demo.twilio.com/docs/voice.xml',
|
|
||||||
to=to,
|
|
||||||
from_=from_
|
|
||||||
)
|
|
||||||
|
|
||||||
print(call.sid)
|
|
||||||
@ -80,9 +80,9 @@ class Twilio:
|
|||||||
resp = VoiceResponse()
|
resp = VoiceResponse()
|
||||||
dial = Dial(
|
dial = Dial(
|
||||||
caller_id=from_number,
|
caller_id=from_number,
|
||||||
record=self.settings.record_calls,
|
# record=self.settings.record_calls,
|
||||||
recording_status_callback=self.get_recording_status_callback_url(),
|
# recording_status_callback=self.get_recording_status_callback_url(),
|
||||||
recording_status_callback_event='completed'
|
# recording_status_callback_event='completed'
|
||||||
)
|
)
|
||||||
dial.number(to_number)
|
dial.number(to_number)
|
||||||
resp.append(dial)
|
resp.append(dial)
|
||||||
@ -97,9 +97,9 @@ class Twilio:
|
|||||||
resp = VoiceResponse()
|
resp = VoiceResponse()
|
||||||
dial = Dial(
|
dial = Dial(
|
||||||
ring_tone=ring_tone,
|
ring_tone=ring_tone,
|
||||||
record=self.settings.record_calls,
|
# record=self.settings.record_calls,
|
||||||
recording_status_callback=self.get_recording_status_callback_url(),
|
# recording_status_callback=self.get_recording_status_callback_url(),
|
||||||
recording_status_callback_event='completed'
|
# recording_status_callback_event='completed'
|
||||||
)
|
)
|
||||||
dial.client(client)
|
dial.client(client)
|
||||||
resp.append(dial)
|
resp.append(dial)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="max-w-[81.7%] bg-white pl-16 p-4 pt-2 z-20">
|
<div class="max-w-[81.7%] pl-16 p-4 pt-2">
|
||||||
<button
|
<button
|
||||||
class="flex gap-2 w-full items-center rounded-lg p-1 bg-gray-100 hover:bg-gray-200"
|
class="flex gap-2 w-full items-center rounded-lg p-1 bg-gray-100 hover:bg-gray-200"
|
||||||
@click="showCommunicationBox = true"
|
@click="showCommunicationBox = true"
|
||||||
@ -10,7 +10,7 @@
|
|||||||
<Tooltip text="Make a call..." class="m-1">
|
<Tooltip text="Make a call..." class="m-1">
|
||||||
<PhoneIcon
|
<PhoneIcon
|
||||||
class="bg-gray-900 rounded-full text-white fill-white p-[3px]"
|
class="bg-gray-900 rounded-full text-white fill-white p-[3px]"
|
||||||
@click.stop="makeOutgoingCall"
|
@click.stop="openPhoneCallDialog"
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</button>
|
</button>
|
||||||
@ -47,6 +47,78 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Dialog
|
||||||
|
v-model="showPhoneCall"
|
||||||
|
:options="{
|
||||||
|
title: 'Make a call...',
|
||||||
|
actions: [{ label: 'Make a call...', variant: 'solid' }],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #body-content>
|
||||||
|
<div>Make a call to +917666980887</div>
|
||||||
|
</template>
|
||||||
|
<template #actions="{ close }">
|
||||||
|
<div class="flex flex-row-reverse gap-2">
|
||||||
|
<Button
|
||||||
|
variant="solid"
|
||||||
|
label="Make a call..."
|
||||||
|
@click="makeOutgoingCall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
<div
|
||||||
|
v-show="showIncomingCall"
|
||||||
|
ref="incomingCallPopup"
|
||||||
|
class="fixed select-none z-10 bg-white rounded-lg shadow-lg p-4 flex flex-col gap-4 w-60"
|
||||||
|
:style="style"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>Incoming Call...</div>
|
||||||
|
<DragIcon ref="incomingCallHandle" class="w-4 h-4 cursor-move" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col justify-center items-center gap-2">
|
||||||
|
<UserAvatar
|
||||||
|
:user="getUser().name"
|
||||||
|
class="flex items-center justify-center !h-24 !w-24 relative pulse"
|
||||||
|
/>
|
||||||
|
<div class="text-xl font-medium">{{ getUser().full_name }}</div>
|
||||||
|
<div class="text-sm text-gray-500">+917666980887</div>
|
||||||
|
<div v-if="onCall" class="flex gap-2">
|
||||||
|
<Button :icon="muted ? 'mic-off' : 'mic'" @click="toggleMute" />
|
||||||
|
<Button
|
||||||
|
variant="solid"
|
||||||
|
theme="red"
|
||||||
|
icon="phone-off"
|
||||||
|
@click="rejectIncomingCall"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="flex gap-2 text-sm mt-2">
|
||||||
|
<Button
|
||||||
|
size="md"
|
||||||
|
variant="solid"
|
||||||
|
theme="green"
|
||||||
|
label="Accept"
|
||||||
|
@click="acceptIncomingCall"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<PhoneIcon class="text-white fill-white h-4 w-4" />
|
||||||
|
</template>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="md"
|
||||||
|
variant="solid"
|
||||||
|
theme="red"
|
||||||
|
label="Reject"
|
||||||
|
@click="rejectIncomingCall"
|
||||||
|
>
|
||||||
|
<template #prefix>
|
||||||
|
<PhoneIcon class="text-white fill-white h-4 w-4 rotate-[135deg]" />
|
||||||
|
</template>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -54,9 +126,11 @@ import UserAvatar from '@/components/UserAvatar.vue'
|
|||||||
import EmailEditor from '@/components/EmailEditor.vue'
|
import EmailEditor from '@/components/EmailEditor.vue'
|
||||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||||
import { usersStore } from '@/stores/users'
|
import { usersStore } from '@/stores/users'
|
||||||
import { Tooltip, call } from 'frappe-ui'
|
import { Tooltip, Dialog, call } from 'frappe-ui'
|
||||||
import { ref, watch, computed, defineModel, onMounted } from 'vue'
|
import { ref, watch, computed, defineModel } from 'vue'
|
||||||
import { Device } from '@twilio/voice-sdk'
|
import { Device } from '@twilio/voice-sdk'
|
||||||
|
import { useDraggable, useWindowSize } from '@vueuse/core'
|
||||||
|
import DragIcon from '@/components/Icons/DragIcon.vue'
|
||||||
|
|
||||||
const modelValue = defineModel()
|
const modelValue = defineModel()
|
||||||
|
|
||||||
@ -107,12 +181,28 @@ async function submitComment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let device = ''
|
let device = ''
|
||||||
let muted = ref(false)
|
|
||||||
let onPhone = ref(false)
|
|
||||||
let log = ref('Connecting...')
|
let log = ref('Connecting...')
|
||||||
let connection = ref(null)
|
let incomingCall = ref(null)
|
||||||
|
let showPhoneCall = ref(false)
|
||||||
|
|
||||||
onMounted(() => startupClient())
|
let showIncomingCall = ref(false)
|
||||||
|
let onCall = ref(false)
|
||||||
|
let muted = ref(false)
|
||||||
|
let incomingCallPopup = ref(null)
|
||||||
|
let incomingCallHandle = ref(null)
|
||||||
|
|
||||||
|
const { width, height } = useWindowSize()
|
||||||
|
|
||||||
|
let { style } = useDraggable(incomingCallPopup, {
|
||||||
|
initialValue: { x: width.value - 280, y: height.value - 300 },
|
||||||
|
handle: incomingCallHandle,
|
||||||
|
preventDefault: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
function openPhoneCallDialog() {
|
||||||
|
showPhoneCall.value = true
|
||||||
|
startupClient()
|
||||||
|
}
|
||||||
|
|
||||||
async function startupClient() {
|
async function startupClient() {
|
||||||
log.value = 'Requesting Access Token...'
|
log.value = 'Requesting Access Token...'
|
||||||
@ -144,8 +234,6 @@ function addDeviceListeners() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
device.on('unregistered', (device) => {
|
device.on('unregistered', (device) => {
|
||||||
onPhone.value = false
|
|
||||||
connection.value = null
|
|
||||||
log.value = 'Logged out'
|
log.value = 'Logged out'
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -153,12 +241,54 @@ function addDeviceListeners() {
|
|||||||
log.value = 'Twilio.Device Error: ' + error.message
|
log.value = 'Twilio.Device Error: ' + error.message
|
||||||
})
|
})
|
||||||
|
|
||||||
|
device.on('incoming', handleIncomingCall)
|
||||||
|
|
||||||
device.on('connect', (conn) => {
|
device.on('connect', (conn) => {
|
||||||
connection.value = conn
|
|
||||||
log.value = 'Successfully established call!'
|
log.value = 'Successfully established call!'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleMute() {
|
||||||
|
if (incomingCall.value.isMuted()) {
|
||||||
|
incomingCall.value.mute(false)
|
||||||
|
muted.value = false
|
||||||
|
} else {
|
||||||
|
incomingCall.value.mute()
|
||||||
|
muted.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleIncomingCall(call) {
|
||||||
|
log.value = `Incoming call from ${call.parameters.From}`
|
||||||
|
|
||||||
|
showIncomingCall.value = true
|
||||||
|
incomingCall.value = call
|
||||||
|
|
||||||
|
// add event listener to call object
|
||||||
|
call.on('cancel', handleDisconnectedIncomingCall)
|
||||||
|
call.on('disconnect', handleDisconnectedIncomingCall)
|
||||||
|
call.on('reject', handleDisconnectedIncomingCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
function acceptIncomingCall() {
|
||||||
|
incomingCall.value.accept()
|
||||||
|
|
||||||
|
log.value = 'Accepted incoming call.'
|
||||||
|
onCall.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function rejectIncomingCall() {
|
||||||
|
incomingCall.value.reject()
|
||||||
|
log.value = 'Rejected incoming call'
|
||||||
|
showIncomingCall.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDisconnectedIncomingCall() {
|
||||||
|
log.value = `Call ended.`
|
||||||
|
showIncomingCall.value = false
|
||||||
|
incomingCall.value = null
|
||||||
|
}
|
||||||
|
|
||||||
async function makeOutgoingCall() {
|
async function makeOutgoingCall() {
|
||||||
if (device) {
|
if (device) {
|
||||||
log.value = `Attempting to call +917666980887 ...`
|
log.value = `Attempting to call +917666980887 ...`
|
||||||
@ -185,3 +315,43 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pulse::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid green;
|
||||||
|
width: calc(100% + 20px);
|
||||||
|
height: calc(100% + 20px);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pulse::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid green;
|
||||||
|
width: calc(100% + 20px);
|
||||||
|
height: calc(100% + 20px);
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 1s linear infinite;
|
||||||
|
animation-delay: 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% {
|
||||||
|
transform: scale(0.5);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: scale(1.3);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user