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()
|
||||
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()
|
||||
dial = Dial(
|
||||
caller_id=from_number,
|
||||
record=self.settings.record_calls,
|
||||
recording_status_callback=self.get_recording_status_callback_url(),
|
||||
recording_status_callback_event='completed'
|
||||
# record=self.settings.record_calls,
|
||||
# recording_status_callback=self.get_recording_status_callback_url(),
|
||||
# recording_status_callback_event='completed'
|
||||
)
|
||||
dial.number(to_number)
|
||||
resp.append(dial)
|
||||
@ -97,9 +97,9 @@ class Twilio:
|
||||
resp = VoiceResponse()
|
||||
dial = Dial(
|
||||
ring_tone=ring_tone,
|
||||
record=self.settings.record_calls,
|
||||
recording_status_callback=self.get_recording_status_callback_url(),
|
||||
recording_status_callback_event='completed'
|
||||
# record=self.settings.record_calls,
|
||||
# recording_status_callback=self.get_recording_status_callback_url(),
|
||||
# recording_status_callback_event='completed'
|
||||
)
|
||||
dial.client(client)
|
||||
resp.append(dial)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<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
|
||||
class="flex gap-2 w-full items-center rounded-lg p-1 bg-gray-100 hover:bg-gray-200"
|
||||
@click="showCommunicationBox = true"
|
||||
@ -10,7 +10,7 @@
|
||||
<Tooltip text="Make a call..." class="m-1">
|
||||
<PhoneIcon
|
||||
class="bg-gray-900 rounded-full text-white fill-white p-[3px]"
|
||||
@click.stop="makeOutgoingCall"
|
||||
@click.stop="openPhoneCallDialog"
|
||||
/>
|
||||
</Tooltip>
|
||||
</button>
|
||||
@ -47,6 +47,78 @@
|
||||
/>
|
||||
</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>
|
||||
|
||||
<script setup>
|
||||
@ -54,9 +126,11 @@ import UserAvatar from '@/components/UserAvatar.vue'
|
||||
import EmailEditor from '@/components/EmailEditor.vue'
|
||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||
import { usersStore } from '@/stores/users'
|
||||
import { Tooltip, call } from 'frappe-ui'
|
||||
import { ref, watch, computed, defineModel, onMounted } from 'vue'
|
||||
import { Tooltip, Dialog, call } from 'frappe-ui'
|
||||
import { ref, watch, computed, defineModel } from 'vue'
|
||||
import { Device } from '@twilio/voice-sdk'
|
||||
import { useDraggable, useWindowSize } from '@vueuse/core'
|
||||
import DragIcon from '@/components/Icons/DragIcon.vue'
|
||||
|
||||
const modelValue = defineModel()
|
||||
|
||||
@ -107,12 +181,28 @@ async function submitComment() {
|
||||
}
|
||||
|
||||
let device = ''
|
||||
let muted = ref(false)
|
||||
let onPhone = ref(false)
|
||||
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() {
|
||||
log.value = 'Requesting Access Token...'
|
||||
@ -144,8 +234,6 @@ function addDeviceListeners() {
|
||||
})
|
||||
|
||||
device.on('unregistered', (device) => {
|
||||
onPhone.value = false
|
||||
connection.value = null
|
||||
log.value = 'Logged out'
|
||||
})
|
||||
|
||||
@ -153,12 +241,54 @@ function addDeviceListeners() {
|
||||
log.value = 'Twilio.Device Error: ' + error.message
|
||||
})
|
||||
|
||||
device.on('incoming', handleIncomingCall)
|
||||
|
||||
device.on('connect', (conn) => {
|
||||
connection.value = conn
|
||||
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() {
|
||||
if (device) {
|
||||
log.value = `Attempting to call +917666980887 ...`
|
||||
@ -185,3 +315,43 @@ watch(
|
||||
{ immediate: true }
|
||||
)
|
||||
</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