1
0
forked from test/crm

fix: merged twilio & exotel settings in one calling settings

This commit is contained in:
Shariq Ansari 2025-01-15 19:29:19 +05:30
parent b921ce9dff
commit 2dfe75931a
4 changed files with 275 additions and 21 deletions

View File

@ -1,6 +0,0 @@
<template>
<SettingsPage doctype="CRM Exotel Settings" class="p-8" />
</template>
<script setup>
import SettingsPage from '@/components/Settings/SettingsPage.vue'
</script>

View File

@ -56,8 +56,7 @@ import InviteMemberPage from '@/components/Settings/InviteMemberPage.vue'
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
import TwilioSettings from '@/components/Settings/TwilioSettings.vue'
import ExotelSettings from '@/components/Settings/ExotelSettings.vue'
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
import SidebarLink from '@/components/SidebarLink.vue'
import { usersStore } from '@/stores/users'
import {
@ -106,14 +105,9 @@ const tabs = computed(() => {
label: __('Integrations'),
items: [
{
label: __('Twilio'),
label: __('Telephony'),
icon: PhoneIcon,
component: markRaw(TwilioSettings),
},
{
label: __('Exotel'),
icon: PhoneIcon,
component: markRaw(ExotelSettings),
component: markRaw(TelephonySettings),
},
{
label: __('WhatsApp'),

View File

@ -0,0 +1,272 @@
<template>
<div class="flex h-full flex-col gap-8 p-8">
<h2
class="flex gap-2 text-xl font-semibold leading-none h-5 text-ink-gray-9"
>
<div>{{ __('Telephony Settings') }}</div>
<Badge
v-if="twilio.isDirty || exotel.isDirty"
:label="__('Not Saved')"
variant="subtle"
theme="orange"
/>
</h2>
<div
v-if="!twilio.get.loading || !exotel.get.loading"
class="flex-1 flex flex-col gap-8 overflow-y-auto"
>
<!-- General -->
<FormControl
type="select"
v-model="defaultCallingMedium"
:label="__('Default calling medium')"
:options="[
{ label: __(''), value: '' },
{ label: __('Twilio'), value: 'Twilio' },
{ label: __('Exotel'), value: 'Exotel' },
]"
class="w-1/2"
/>
<!-- Twilio -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-9">
{{ __('Twilio') }}
</span>
<FieldLayout
v-if="twilio?.doc && twilioTabs"
:tabs="twilioTabs"
:data="twilio.doc"
doctype="Twilio Settings"
/>
</div>
<!-- Exotel -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-9">
{{ __('Exotel') }}
</span>
<FieldLayout
v-if="exotel?.doc && exotelTabs"
:tabs="exotelTabs"
:data="exotel.doc"
doctype="CRM Exotel Settings"
/>
</div>
</div>
<div v-else class="flex flex-1 items-center justify-center">
<Spinner class="size-8" />
</div>
<div class="flex justify-between gap-2">
<div>
<ErrorMessage class="mt-2" :message="twilio.save.error" />
<ErrorMessage class="mt-2" :message="exotel.save.error" />
</div>
<Button
:loading="twilio.save.loading || exotel.save.loading"
:label="__('Update')"
variant="solid"
@click="update"
/>
</div>
</div>
</template>
<script setup>
import FieldLayout from '@/components/FieldLayout/FieldLayout.vue'
import {
createDocumentResource,
createResource,
FormControl,
Spinner,
Badge,
ErrorMessage,
call,
} from 'frappe-ui'
import { defaultCallingMedium } from '@/composables/settings'
import { createToast, getRandom } from '@/utils'
import { computed } from 'vue'
const twilioFields = createResource({
url: 'crm.api.doc.get_fields',
cache: ['fields', 'Twilio Settings'],
params: {
doctype: 'Twilio Settings',
allow_all_fieldtypes: true,
},
auto: true,
})
const exotelFields = createResource({
url: 'crm.api.doc.get_fields',
cache: ['fields', 'CRM Exotel Settings'],
params: {
doctype: 'CRM Exotel Settings',
allow_all_fieldtypes: true,
},
auto: true,
})
const twilio = createDocumentResource({
doctype: 'Twilio Settings',
name: 'Twilio Settings',
fields: ['*'],
auto: true,
setValue: {
onSuccess: () => {
createToast({
title: __('Success'),
text: __('Twilio settings updated successfully'),
icon: 'check',
iconClasses: 'text-ink-green-3',
})
},
onError: (err) => {
createToast({
title: __('Error'),
text: err.message + ': ' + err.messages[0],
icon: 'x',
iconClasses: 'text-ink-red-4',
})
},
},
})
const exotel = createDocumentResource({
doctype: 'CRM Exotel Settings',
name: 'CRM Exotel Settings',
fields: ['*'],
auto: true,
setValue: {
onSuccess: () => {
createToast({
title: __('Success'),
text: __('Exotel settings updated successfully'),
icon: 'check',
iconClasses: 'text-ink-green-3',
})
},
onError: (err) => {
createToast({
title: __('Error'),
text: err.message + ': ' + err.messages[0],
icon: 'x',
iconClasses: 'text-ink-red-4',
})
},
},
})
const twilioTabs = computed(() => {
if (!twilioFields.data) return []
let _tabs = []
let fieldsData = twilioFields.data
if (fieldsData[0].type != 'Tab Break') {
let _sections = []
if (fieldsData[0].type != 'Section Break') {
_sections.push({
name: 'first_section',
columns: [{ name: 'first_column', fields: [] }],
})
}
_tabs.push({ name: 'first_tab', sections: _sections })
}
fieldsData.forEach((field) => {
let last_tab = _tabs[_tabs.length - 1]
let _sections = _tabs.length ? last_tab.sections : []
if (field.fieldtype === 'Tab Break') {
_tabs.push({
label: field.label,
name: field.fieldname,
sections: [
{
name: 'section_' + getRandom(),
columns: [{ name: 'column_' + getRandom(), fields: [] }],
},
],
})
} else if (field.fieldtype === 'Section Break') {
_sections.push({
label: field.label,
name: field.fieldname,
columns: [{ name: 'column_' + getRandom(), fields: [] }],
})
} else if (field.fieldtype === 'Column Break') {
_sections[_sections.length - 1].columns.push({
name: field.fieldname,
fields: [],
})
} else {
let last_section = _sections[_sections.length - 1]
let last_column = last_section.columns[last_section.columns.length - 1]
last_column.fields.push(field)
}
})
return _tabs
})
const exotelTabs = computed(() => {
if (!exotelFields.data) return []
let _tabs = []
let fieldsData = exotelFields.data
if (fieldsData[0].type != 'Tab Break') {
let _sections = []
if (fieldsData[0].type != 'Section Break') {
_sections.push({
name: 'first_section',
columns: [{ name: 'first_column', fields: [] }],
})
}
_tabs.push({ name: 'first_tab', sections: _sections })
}
fieldsData.forEach((field) => {
let last_tab = _tabs[_tabs.length - 1]
let _sections = _tabs.length ? last_tab.sections : []
if (field.fieldtype === 'Tab Break') {
_tabs.push({
label: field.label,
name: field.fieldname,
sections: [
{
name: 'section_' + getRandom(),
columns: [{ name: 'column_' + getRandom(), fields: [] }],
},
],
})
} else if (field.fieldtype === 'Section Break') {
_sections.push({
label: field.label,
name: field.fieldname,
columns: [{ name: 'column_' + getRandom(), fields: [] }],
})
} else if (field.fieldtype === 'Column Break') {
_sections[_sections.length - 1].columns.push({
name: field.fieldname,
fields: [],
})
} else {
let last_section = _sections[_sections.length - 1]
let last_column = last_section.columns[last_section.columns.length - 1]
last_column.fields.push(field)
}
})
return _tabs
})
async function update() {
call('crm.integrations.api.set_default_calling_medium', {
medium: defaultCallingMedium.value,
})
if (twilio.isDirty) {
twilio.save.submit()
}
if (exotel.isDirty) {
exotel.save.submit()
}
}
</script>

View File

@ -1,6 +0,0 @@
<template>
<SettingsPage doctype="Twilio Settings" class="p-8" />
</template>
<script setup>
import SettingsPage from '@/components/Settings/SettingsPage.vue'
</script>