fix: merged twilio & exotel settings in one calling settings
This commit is contained in:
parent
b921ce9dff
commit
2dfe75931a
@ -1,6 +0,0 @@
|
|||||||
<template>
|
|
||||||
<SettingsPage doctype="CRM Exotel Settings" class="p-8" />
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import SettingsPage from '@/components/Settings/SettingsPage.vue'
|
|
||||||
</script>
|
|
||||||
@ -56,8 +56,7 @@ import InviteMemberPage from '@/components/Settings/InviteMemberPage.vue'
|
|||||||
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
|
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
|
||||||
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
|
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
|
||||||
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
|
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
|
||||||
import TwilioSettings from '@/components/Settings/TwilioSettings.vue'
|
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
|
||||||
import ExotelSettings from '@/components/Settings/ExotelSettings.vue'
|
|
||||||
import SidebarLink from '@/components/SidebarLink.vue'
|
import SidebarLink from '@/components/SidebarLink.vue'
|
||||||
import { usersStore } from '@/stores/users'
|
import { usersStore } from '@/stores/users'
|
||||||
import {
|
import {
|
||||||
@ -106,14 +105,9 @@ const tabs = computed(() => {
|
|||||||
label: __('Integrations'),
|
label: __('Integrations'),
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
label: __('Twilio'),
|
label: __('Telephony'),
|
||||||
icon: PhoneIcon,
|
icon: PhoneIcon,
|
||||||
component: markRaw(TwilioSettings),
|
component: markRaw(TelephonySettings),
|
||||||
},
|
|
||||||
{
|
|
||||||
label: __('Exotel'),
|
|
||||||
icon: PhoneIcon,
|
|
||||||
component: markRaw(ExotelSettings),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: __('WhatsApp'),
|
label: __('WhatsApp'),
|
||||||
|
|||||||
272
frontend/src/components/Settings/TelephonySettings.vue
Normal file
272
frontend/src/components/Settings/TelephonySettings.vue
Normal 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>
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<template>
|
|
||||||
<SettingsPage doctype="Twilio Settings" class="p-8" />
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import SettingsPage from '@/components/Settings/SettingsPage.vue'
|
|
||||||
</script>
|
|
||||||
Loading…
x
Reference in New Issue
Block a user