Skip to content

Commit

Permalink
Merge pull request #21 from shariquerik/twilio-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
shariquerik authored Nov 3, 2023
2 parents 412565f + 0904ba3 commit a8c32cf
Show file tree
Hide file tree
Showing 11 changed files with 3,583 additions and 1,842 deletions.
22 changes: 17 additions & 5 deletions crm/fcrm/doctype/twilio_settings/twilio_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"section_break_malx",
"account_sid",
"api_key",
"api_secret",
"column_break_idds",
"auth_token",
"twiml_sid",
"section_break_ssqj",
"record_calls",
"column_break_avmt"
"enabled",
"column_break_avmt",
"record_calls"
],
"fields": [
{
"fieldname": "account_sid",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Account SID",
"reqd": 1
"mandatory_depends_on": "eval: doc.enabled"
},
{
"fieldname": "api_key",
Expand All @@ -46,7 +48,7 @@
"fieldtype": "Password",
"in_list_view": 1,
"label": "Auth Token",
"reqd": 1
"mandatory_depends_on": "eval: doc.enabled"
},
{
"fieldname": "twiml_sid",
Expand All @@ -67,12 +69,22 @@
{
"fieldname": "column_break_avmt",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_malx",
"fieldtype": "Section Break"
},
{
"default": "0",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2023-09-20 16:42:17.025651",
"modified": "2023-11-03 15:13:09.155818",
"modified_by": "Administrator",
"module": "FCRM",
"name": "Twilio Settings",
Expand Down
4 changes: 4 additions & 0 deletions crm/twilio/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
from frappe import _
from .twilio_handler import Twilio, IncomingCall, TwilioCallDetails

@frappe.whitelist()
def is_enabled():
return frappe.db.get_single_value("Twilio Settings", "enabled")

@frappe.whitelist()
def generate_access_token():
"""Returns access token that is required to authenticate Twilio Client SDK.
Expand Down
6 changes: 4 additions & 2 deletions crm/twilio/twilio_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ def connect(self):
"""Make a twilio connection.
"""
settings = frappe.get_doc("Twilio Settings")
# if not (settings and settings.enabled):
# return
if not (settings and settings.enabled):
return
return Twilio(settings=settings)

def get_phone_numbers(self):
Expand Down Expand Up @@ -115,6 +115,8 @@ def generate_twilio_client_response(self, client, ring_tone='at'):
@classmethod
def get_twilio_client(self):
twilio_settings = frappe.get_doc("Twilio Settings")
if not twilio_settings.enabled:
frappe.throw(_("Please enable twilio settings before making a call."))

auth_token = get_decrypted_password("Twilio Settings", "Twilio Settings", 'auth_token')
client = TwilioClient(twilio_settings.account_sid, auth_token)
Expand Down
12 changes: 7 additions & 5 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@
"serve": "vite preview"
},
"dependencies": {
"@tiptap/vue-3": "^2.0.4",
"@twilio/voice-sdk": "^2.7.1",
"@vitejs/plugin-vue": "^4.2.3",
"@vueuse/core": "^10.3.0",
"@vueuse/integrations": "^10.3.0",
"autoprefixer": "^10.4.14",
"feather-icons": "^4.28.0",
"frappe-ui": "^0.1.12",
"frappe-ui": "^0.1.14",
"pinia": "^2.0.33",
"postcss": "^8.4.5",
"socket.io-client": "^4.7.2",
"sortablejs": "^1.15.0",
"tailwindcss": "^3.3.3",
"vite": "^4.4.9",
"vue": "^3.3.4",
"vue-router": "^4.2.2"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.5",
"vite": "^4.4.9"
}
}
59 changes: 34 additions & 25 deletions frontend/src/components/CallUI.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
<div
v-show="showCallPopup"
ref="callPopup"
class="fixed select-none z-10 bg-gray-900 text-gray-300 rounded-lg shadow-2xl p-4 flex flex-col w-60 cursor-move"
class="fixed z-10 flex w-60 cursor-move select-none flex-col rounded-lg bg-gray-900 p-4 text-gray-300 shadow-2xl"
:style="style"
>
<div class="flex items-center flex-row-reverse gap-1">
<MinimizeIcon class="w-4 h-4 cursor-pointer" @click="toggleCallWindow" />
<div class="flex flex-row-reverse items-center gap-1">
<MinimizeIcon class="h-4 w-4 cursor-pointer" @click="toggleCallWindow" />
</div>
<div class="flex flex-col justify-center items-center gap-3">
<div class="flex flex-col items-center justify-center gap-3">
<Avatar
:image="contact.image"
:label="contact.full_name"
class="flex items-center justify-center [&>div]:text-[30px] !h-24 !w-24 relative"
class="relative flex !h-24 !w-24 items-center justify-center [&>div]:text-[30px]"
:class="onCall || calling ? '' : 'pulse'"
/>
<div class="flex flex-col items-center justify-center gap-1">
Expand All @@ -22,11 +22,11 @@
<div class="text-sm text-gray-600">{{ contact.mobile_no }}</div>
</div>
<CountUpTimer ref="counterUp">
<div v-if="onCall" class="text-base my-1">
<div v-if="onCall" class="my-1 text-base">
{{ counterUp?.updatedTime }}
</div>
</CountUpTimer>
<div v-if="!onCall" class="text-base my-1">
<div v-if="!onCall" class="my-1 text-base">
{{
callStatus == 'ringing'
? 'Ringing...'
Expand All @@ -43,21 +43,21 @@
/>
<Button class="rounded-full">
<template #icon>
<DialpadIcon class="rounded-full cursor-pointer" />
<DialpadIcon class="cursor-pointer rounded-full" />
</template>
</Button>
<Button class="rounded-full">
<template #icon>
<NoteIcon
class="text-gray-900 rounded-full cursor-pointer h-4 w-4"
class="h-4 w-4 cursor-pointer rounded-full text-gray-900"
@click="showNoteModal = true"
/>
</template>
</Button>
<Button class="rounded-full bg-red-600 hover:bg-red-700">
<template #icon>
<PhoneIcon
class="text-white fill-white h-4 w-4 rotate-[135deg]"
class="h-4 w-4 rotate-[135deg] fill-white text-white"
@click="hangUpCall"
/>
</template>
Expand All @@ -73,7 +73,7 @@
class="rounded-lg"
>
<template #prefix>
<PhoneIcon class="fill-white h-4 w-4 rotate-[135deg]" />
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div>
Expand All @@ -87,7 +87,7 @@
@click="acceptIncomingCall"
>
<template #prefix>
<PhoneIcon class="fill-white h-4 w-4" />
<PhoneIcon class="h-4 w-4 fill-white" />
</template>
</Button>
<Button
Expand All @@ -99,35 +99,35 @@
@click="rejectIncomingCall"
>
<template #prefix>
<PhoneIcon class="fill-white h-4 w-4 rotate-[135deg]" />
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div>
</div>
</div>
<div
v-show="showSmallCallWindow"
class="flex items-center justify-between gap-3 bg-gray-900 text-base text-gray-300 ml-2 px-2 py-[7px] rounded-lg cursor-pointer select-none"
class="ml-2 flex cursor-pointer select-none items-center justify-between gap-3 rounded-lg bg-gray-900 px-2 py-[7px] text-base text-gray-300"
@click="toggleCallWindow"
>
<div class="flex items-center gap-2">
<Avatar
:image="contact.image"
:label="contact.full_name"
class="flex items-center justify-center !h-5 !w-5 relative"
class="relative flex !h-5 !w-5 items-center justify-center"
/>
<div class="truncate max-w-[120px]">
<div class="max-w-[120px] truncate">
{{ contact.full_name }}
</div>
</div>
<div v-if="onCall" class="flex items-center gap-2">
<div class="my-1 min-w-[40px] text-center">
{{ counterUp?.updatedTime }}
</div>
<Button variant="solid" theme="red" class="rounded-full !h-6 !w-6">
<Button variant="solid" theme="red" class="!h-6 !w-6 rounded-full">
<template #icon>
<PhoneIcon
class="fill-white h-4 w-4 rotate-[135deg]"
class="h-4 w-4 rotate-[135deg] fill-white"
@click.stop="hangUpCall"
/>
</template>
Expand All @@ -140,33 +140,33 @@
<Button
variant="solid"
theme="red"
class="rounded-full !h-6 !w-6"
class="!h-6 !w-6 rounded-full"
@click.stop="cancelCall"
>
<template #icon>
<PhoneIcon class="fill-white h-4 w-4 rotate-[135deg]" />
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div>
<div v-else class="flex items-center gap-2">
<Button
variant="solid"
theme="green"
class="rounded-full !h-6 !w-6 pulse relative"
class="pulse relative !h-6 !w-6 rounded-full"
@click.stop="acceptIncomingCall"
>
<template #icon>
<PhoneIcon class="fill-white h-4 w-4 animate-pulse" />
<PhoneIcon class="h-4 w-4 animate-pulse fill-white" />
</template>
</Button>
<Button
variant="solid"
theme="red"
class="rounded-full !h-6 !w-6"
class="!h-6 !w-6 rounded-full"
@click.stop="rejectIncomingCall"
>
<template #icon>
<PhoneIcon class="fill-white h-4 w-4 rotate-[135deg]" />
<PhoneIcon class="h-4 w-4 rotate-[135deg] fill-white" />
</template>
</Button>
</div>
Expand Down Expand Up @@ -197,6 +197,7 @@ const contact = ref({
mobile_no: '',
})
let enabled = ref(false)
let showCallPopup = ref(false)
let showSmallCallWindow = ref(false)
let onCall = ref(false)
Expand Down Expand Up @@ -244,6 +245,10 @@ let { style } = useDraggable(callPopup, {
preventDefault: true,
})
async function is_twilio_enabled() {
return await call('crm.twilio.api.is_enabled')
}
async function startupClient() {
log.value = 'Requesting Access Token...'
Expand Down Expand Up @@ -469,7 +474,10 @@ function toggleCallWindow() {
}
}
onMounted(() => startupClient())
onMounted(async () => {
enabled.value = await is_twilio_enabled()
enabled.value && startupClient()
})
watch(
() => log.value,
Expand All @@ -481,6 +489,7 @@ watch(
const app = getCurrentInstance()
app.appContext.config.globalProperties.makeCall = makeOutgoingCall
app.appContext.config.globalProperties.is_twilio_enabled = enabled.value
</script>

<style scoped>
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/composables/twilio.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { getCurrentInstance } from 'vue'

export function is_twilio_enabled() {
const app = getCurrentInstance()
return app.appContext.config.globalProperties.is_twilio_enabled
}
27 changes: 19 additions & 8 deletions frontend/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,34 @@ import frappeui from 'frappe-ui/vite'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [frappeui(), vue({
script: {
defineModel: true,
propsDestructure: true
}
})],
plugins: [
frappeui(),
vue({
script: {
defineModel: true,
propsDestructure: true,
},
}),
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
build: {
outDir: `../${path.basename(path.resolve('..'))}/public/frontend`,
outDir: '../crm/public/frontend',
emptyOutDir: true,
commonjsOptions: {
include: [/tailwind.config.js/, /node_modules/],
},
sourcemap: true,
},
optimizeDeps: {
include: ['frappe-ui > feather-icons', 'showdown', 'engine.io-client'],
include: [
'feather-icons',
'showdown',
'tailwind.config.js',
'engine.io-client',
],
},
})
Loading

0 comments on commit a8c32cf

Please sign in to comment.