fix: created Section Component using Toggler component and used in lead/deal
This commit is contained in:
parent
36455b8faf
commit
b157f255f8
56
frontend/src/components/Section.vue
Normal file
56
frontend/src/components/Section.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<slot name="header" v-bind="{ opened, open, close, toggle }">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="flex h-7 max-w-fit cursor-pointer items-center gap-2 pl-2 pr-3 text-base font-semibold leading-5"
|
||||||
|
@click="toggle()"
|
||||||
|
>
|
||||||
|
<FeatherIcon
|
||||||
|
name="chevron-right"
|
||||||
|
class="h-4 text-gray-900 transition-all duration-300 ease-in-out"
|
||||||
|
:class="{ 'rotate-90': opened }"
|
||||||
|
/>
|
||||||
|
{{ label || 'Untitled' }}
|
||||||
|
</div>
|
||||||
|
<slot name="actions"></slot>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
<transition
|
||||||
|
enter-active-class="duration-300 ease-in"
|
||||||
|
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
||||||
|
enter-to-class="max-h-[200px] overflow-hidden"
|
||||||
|
leave-from-class="max-h-[200px] overflow-hidden"
|
||||||
|
enter-from-class="max-h-0 overflow-hidden"
|
||||||
|
leave-to-class="max-h-0 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div v-if="opened">
|
||||||
|
<slot v-bind="{ opened, open, close, toggle }" />
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { FeatherIcon } from 'frappe-ui'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
const props = defineProps({
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isOpened: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
function toggle() {
|
||||||
|
opened.value = !opened.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
opened.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
opened.value = false
|
||||||
|
}
|
||||||
|
let opened = ref(props.isOpened)
|
||||||
|
</script>
|
||||||
@ -1,69 +1,71 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div class="flex flex-col gap-1.5">
|
||||||
v-for="field in fields"
|
<div
|
||||||
:key="field.label"
|
v-for="field in fields"
|
||||||
class="flex items-center gap-2 px-3 text-base leading-5 first:mt-3"
|
:key="field.label"
|
||||||
>
|
class="flex items-center gap-2 px-3 text-base leading-5 first:mt-3"
|
||||||
<div class="w-[106px] shrink-0 text-gray-600">
|
>
|
||||||
{{ field.label }}
|
<div class="w-[106px] shrink-0 text-gray-600">
|
||||||
</div>
|
{{ field.label }}
|
||||||
<div class="flex-1 overflow-hidden">
|
</div>
|
||||||
<Link
|
<div class="flex-1 overflow-hidden">
|
||||||
v-if="field.type === 'link'"
|
<Link
|
||||||
class="form-control"
|
v-if="field.type === 'link'"
|
||||||
:value="data[field.name]"
|
class="form-control"
|
||||||
:doctype="field.doctype"
|
:value="data[field.name]"
|
||||||
:placeholder="field.placeholder"
|
:doctype="field.doctype"
|
||||||
@change="(data) => emit('update', field.name, data)"
|
:placeholder="field.placeholder"
|
||||||
:onCreate="field.create"
|
@change="(data) => emit('update', field.name, data)"
|
||||||
/>
|
:onCreate="field.create"
|
||||||
<FormControl
|
/>
|
||||||
v-else-if="field.type === 'select'"
|
<FormControl
|
||||||
class="form-control cursor-pointer [&_select]:cursor-pointer"
|
v-else-if="field.type === 'select'"
|
||||||
type="select"
|
class="form-control cursor-pointer [&_select]:cursor-pointer"
|
||||||
:value="data[field.name]"
|
type="select"
|
||||||
:options="field.options"
|
:value="data[field.name]"
|
||||||
:debounce="500"
|
:options="field.options"
|
||||||
@change.stop="emit('update', field.name, $event.target.value)"
|
:debounce="500"
|
||||||
/>
|
@change.stop="emit('update', field.name, $event.target.value)"
|
||||||
<FormControl
|
/>
|
||||||
v-else-if="field.type === 'email'"
|
<FormControl
|
||||||
class="form-control"
|
v-else-if="field.type === 'email'"
|
||||||
type="email"
|
class="form-control"
|
||||||
:value="data[field.name]"
|
type="email"
|
||||||
:debounce="500"
|
:value="data[field.name]"
|
||||||
@change.stop="emit('update', field.name, $event.target.value)"
|
:debounce="500"
|
||||||
/>
|
@change.stop="emit('update', field.name, $event.target.value)"
|
||||||
<FormControl
|
/>
|
||||||
v-else-if="field.type === 'date'"
|
<FormControl
|
||||||
class="form-control"
|
v-else-if="field.type === 'date'"
|
||||||
type="date"
|
class="form-control"
|
||||||
:value="data[field.name]"
|
type="date"
|
||||||
:debounce="500"
|
:value="data[field.name]"
|
||||||
@change.stop="emit('update', field.name, $event.target.value)"
|
:debounce="500"
|
||||||
/>
|
@change.stop="emit('update', field.name, $event.target.value)"
|
||||||
<Tooltip
|
/>
|
||||||
v-else-if="field.type === 'read_only'"
|
<Tooltip
|
||||||
class="flex h-7 cursor-pointer items-center px-2 py-1"
|
v-else-if="field.type === 'read_only'"
|
||||||
:text="field.tooltip"
|
class="flex h-7 cursor-pointer items-center px-2 py-1"
|
||||||
>
|
:text="field.tooltip"
|
||||||
{{ field.value }}
|
>
|
||||||
</Tooltip>
|
{{ field.value }}
|
||||||
<FormControl
|
</Tooltip>
|
||||||
v-else
|
<FormControl
|
||||||
class="form-control"
|
v-else
|
||||||
type="text"
|
class="form-control"
|
||||||
:value="data[field.name]"
|
type="text"
|
||||||
:placeholder="field.placeholder"
|
:value="data[field.name]"
|
||||||
:debounce="500"
|
:placeholder="field.placeholder"
|
||||||
@change.stop="emit('update', field.name, $event.target.value)"
|
:debounce="500"
|
||||||
|
@change.stop="emit('update', field.name, $event.target.value)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<ExternalLinkIcon
|
||||||
|
v-if="field.type === 'link' && field.link && data[field.name]"
|
||||||
|
class="h-4 w-4 shrink-0 cursor-pointer text-gray-600"
|
||||||
|
@click="field.link(data[field.name])"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ExternalLinkIcon
|
|
||||||
v-if="field.type === 'link' && field.link && data[field.name]"
|
|
||||||
class="h-4 w-4 shrink-0 cursor-pointer text-gray-600"
|
|
||||||
@click="field.link(data[field.name])"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
<template>
|
|
||||||
<slot v-bind="{ opened, open, close, toggle }"></slot>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
const props = defineProps({
|
|
||||||
isOpened: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
function toggle() {
|
|
||||||
opened.value = !opened.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
opened.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
opened.value = false
|
|
||||||
}
|
|
||||||
let opened = ref(props.isOpened)
|
|
||||||
</script>
|
|
||||||
@ -101,19 +101,8 @@
|
|||||||
class="flex flex-col p-3"
|
class="flex flex-col p-3"
|
||||||
:class="{ 'border-b': i !== detailSections.data.length - 1 }"
|
:class="{ 'border-b': i !== detailSections.data.length - 1 }"
|
||||||
>
|
>
|
||||||
<Toggler :is-opened="section.opened" v-slot="{ opened, toggle }">
|
<Section :is-opened="section.opened" :label="section.label">
|
||||||
<div class="flex items-center justify-between">
|
<template #actions>
|
||||||
<div
|
|
||||||
class="flex h-7 max-w-fit cursor-pointer items-center gap-2 pl-2 pr-3 text-base font-semibold leading-5"
|
|
||||||
@click="toggle()"
|
|
||||||
>
|
|
||||||
<FeatherIcon
|
|
||||||
name="chevron-right"
|
|
||||||
class="h-4 text-gray-900 transition-all duration-300 ease-in-out"
|
|
||||||
:class="{ 'rotate-90': opened }"
|
|
||||||
/>
|
|
||||||
{{ section.label }}
|
|
||||||
</div>
|
|
||||||
<div v-if="section.contacts" class="pr-2">
|
<div v-if="section.contacts" class="pr-2">
|
||||||
<Link
|
<Link
|
||||||
value=""
|
value=""
|
||||||
@ -143,129 +132,103 @@
|
|||||||
</template>
|
</template>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<transition
|
<SectionFields
|
||||||
enter-active-class="duration-300 ease-in"
|
v-if="section.fields"
|
||||||
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
:fields="section.fields"
|
||||||
enter-to-class="max-h-[200px] overflow-hidden"
|
v-model="deal.data"
|
||||||
leave-from-class="max-h-[200px] overflow-hidden"
|
@update="updateField"
|
||||||
enter-from-class="max-h-0 overflow-hidden"
|
/>
|
||||||
leave-to-class="max-h-0 overflow-hidden"
|
<div v-else>
|
||||||
>
|
<div
|
||||||
<div v-if="opened" class="flex flex-col gap-1.5">
|
v-if="section.contacts.length"
|
||||||
<SectionFields
|
v-for="(contact, i) in section.contacts"
|
||||||
v-if="section.fields"
|
:key="contact.name"
|
||||||
:fields="section.fields"
|
>
|
||||||
v-model="deal.data"
|
<div
|
||||||
@update="updateField"
|
class="px-2 pb-2.5"
|
||||||
/>
|
:class="[i == 0 ? 'pt-5' : 'pt-2.5']"
|
||||||
<div v-else>
|
>
|
||||||
<div
|
<Section :is-opened="contact.opened">
|
||||||
v-if="section.contacts.length"
|
<template #header="{ opened, toggle }">
|
||||||
v-for="(contact, i) in section.contacts"
|
<div
|
||||||
:key="contact.name"
|
class="flex cursor-pointer items-center justify-between gap-2 pr-1 text-base leading-5 text-gray-700"
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="px-2 pb-2.5"
|
|
||||||
:class="[i == 0 ? 'pt-5' : 'pt-2.5']"
|
|
||||||
>
|
|
||||||
<Toggler
|
|
||||||
:is-opened="contact.opened"
|
|
||||||
v-slot="{ opened: cOpened, toggle: cToggle }"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex cursor-pointer items-center justify-between gap-2 pr-1 text-base leading-5 text-gray-700"
|
class="flex h-7 items-center gap-2"
|
||||||
|
@click="toggle()"
|
||||||
>
|
>
|
||||||
<div
|
<Avatar
|
||||||
class="flex h-7 items-center gap-2"
|
:label="getContactByName(contact.name).full_name"
|
||||||
@click="cToggle()"
|
:image="getContactByName(contact.name).image"
|
||||||
>
|
size="md"
|
||||||
<Avatar
|
/>
|
||||||
:label="
|
{{ getContactByName(contact.name).full_name }}
|
||||||
getContactByName(contact.name).full_name
|
<Badge
|
||||||
"
|
v-if="contact.is_primary"
|
||||||
:image="getContactByName(contact.name).image"
|
class="ml-2"
|
||||||
size="md"
|
variant="outline"
|
||||||
/>
|
label="Primary"
|
||||||
{{ getContactByName(contact.name).full_name }}
|
theme="green"
|
||||||
<Badge
|
/>
|
||||||
v-if="contact.is_primary"
|
</div>
|
||||||
class="ml-2"
|
<div class="flex items-center">
|
||||||
variant="outline"
|
<Dropdown :options="contactOptions(contact)">
|
||||||
label="Primary"
|
<Button variant="ghost">
|
||||||
theme="green"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<Dropdown :options="contactOptions(contact)">
|
|
||||||
<Button variant="ghost">
|
|
||||||
<FeatherIcon
|
|
||||||
name="more-horizontal"
|
|
||||||
class="h-4 text-gray-600"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</Dropdown>
|
|
||||||
<Button
|
|
||||||
variant="ghost"
|
|
||||||
@click="
|
|
||||||
router.push({
|
|
||||||
name: 'Contact',
|
|
||||||
params: { contactId: contact.name },
|
|
||||||
})
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<ExternalLinkIcon class="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
<Button variant="ghost" @click="cToggle()">
|
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
name="chevron-right"
|
name="more-horizontal"
|
||||||
class="h-4 w-4 text-gray-900 transition-all duration-300 ease-in-out"
|
class="h-4 text-gray-600"
|
||||||
:class="{ 'rotate-90': cOpened }"
|
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</Dropdown>
|
||||||
</div>
|
<Button
|
||||||
<transition
|
variant="ghost"
|
||||||
enter-active-class="duration-300 ease-in"
|
@click="
|
||||||
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
router.push({
|
||||||
enter-to-class="max-h-[200px] overflow-hidden"
|
name: 'Contact',
|
||||||
leave-from-class="max-h-[200px] overflow-hidden"
|
params: { contactId: contact.name },
|
||||||
enter-from-class="max-h-0 overflow-hidden"
|
})
|
||||||
leave-to-class="max-h-0 overflow-hidden"
|
"
|
||||||
>
|
|
||||||
<div
|
|
||||||
v-if="cOpened"
|
|
||||||
class="flex flex-col gap-1.5 text-base text-gray-800"
|
|
||||||
>
|
>
|
||||||
<div
|
<ExternalLinkIcon class="h-4 w-4" />
|
||||||
class="flex items-center gap-3 pb-1.5 pl-1 pt-4"
|
</Button>
|
||||||
>
|
<Button variant="ghost" @click="toggle()">
|
||||||
<EmailIcon class="h-4 w-4" />
|
<FeatherIcon
|
||||||
{{ getContactByName(contact.name).email_id }}
|
name="chevron-right"
|
||||||
</div>
|
class="h-4 w-4 text-gray-900 transition-all duration-300 ease-in-out"
|
||||||
<div class="flex items-center gap-3 p-1 py-1.5">
|
:class="{ 'rotate-90': opened }"
|
||||||
<PhoneIcon class="h-4 w-4" />
|
/>
|
||||||
{{ getContactByName(contact.name).mobile_no }}
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</template>
|
||||||
</Toggler>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
v-if="i != section.contacts.length - 1"
|
class="flex flex-col gap-1.5 text-base text-gray-800"
|
||||||
class="mx-2 h-px border-t border-gray-200"
|
>
|
||||||
/>
|
<div class="flex items-center gap-3 pb-1.5 pl-1 pt-4">
|
||||||
</div>
|
<EmailIcon class="h-4 w-4" />
|
||||||
<div
|
{{ getContactByName(contact.name).email_id }}
|
||||||
v-else
|
</div>
|
||||||
class="flex h-20 items-center justify-center text-base text-gray-600"
|
<div class="flex items-center gap-3 p-1 py-1.5">
|
||||||
>
|
<PhoneIcon class="h-4 w-4" />
|
||||||
No contacts added
|
{{ getContactByName(contact.name).mobile_no }}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="i != section.contacts.length - 1"
|
||||||
|
class="mx-2 h-px border-t border-gray-200"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<div
|
||||||
</Toggler>
|
v-else
|
||||||
|
class="flex h-20 items-center justify-center text-base text-gray-600"
|
||||||
|
>
|
||||||
|
No contacts added
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -302,12 +265,12 @@ import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
|||||||
import ExternalLinkIcon from '@/components/Icons/ExternalLinkIcon.vue'
|
import ExternalLinkIcon from '@/components/Icons/ExternalLinkIcon.vue'
|
||||||
import SuccessIcon from '@/components/Icons/SuccessIcon.vue'
|
import SuccessIcon from '@/components/Icons/SuccessIcon.vue'
|
||||||
import LayoutHeader from '@/components/LayoutHeader.vue'
|
import LayoutHeader from '@/components/LayoutHeader.vue'
|
||||||
import Toggler from '@/components/Toggler.vue'
|
|
||||||
import Activities from '@/components/Activities.vue'
|
import Activities from '@/components/Activities.vue'
|
||||||
import UserAvatar from '@/components/UserAvatar.vue'
|
import UserAvatar from '@/components/UserAvatar.vue'
|
||||||
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
||||||
import ContactModal from '@/components/Modals/ContactModal.vue'
|
import ContactModal from '@/components/Modals/ContactModal.vue'
|
||||||
import Link from '@/components/Controls/Link.vue'
|
import Link from '@/components/Controls/Link.vue'
|
||||||
|
import Section from '@/components/Section.vue'
|
||||||
import SectionFields from '@/components/SectionFields.vue'
|
import SectionFields from '@/components/SectionFields.vue'
|
||||||
import {
|
import {
|
||||||
dealStatuses,
|
dealStatuses,
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
:validateFile="validateFile"
|
:validateFile="validateFile"
|
||||||
>
|
>
|
||||||
<template #default="{ openFileSelector, error }">
|
<template #default="{ openFileSelector, error }">
|
||||||
<div class="flex items-center justify-start gap-5 p-5">
|
<div class="flex items-center justify-start gap-5 border-b p-5">
|
||||||
<div class="group relative h-[88px] w-[88px]">
|
<div class="group relative h-[88px] w-[88px]">
|
||||||
<Avatar
|
<Avatar
|
||||||
size="3xl"
|
size="3xl"
|
||||||
@ -135,41 +135,18 @@
|
|||||||
<div class="flex flex-1 flex-col justify-between overflow-hidden">
|
<div class="flex flex-1 flex-col justify-between overflow-hidden">
|
||||||
<div class="flex flex-col overflow-y-auto">
|
<div class="flex flex-col overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
v-for="section in detailSections.data"
|
v-for="(section, i) in detailSections.data"
|
||||||
:key="section.label"
|
:key="section.label"
|
||||||
class="flex flex-col"
|
class="flex flex-col p-3"
|
||||||
|
:class="{ 'border-b': i !== detailSections.data.length - 1 }"
|
||||||
>
|
>
|
||||||
<Toggler :is-opened="section.opened" v-slot="{ opened, toggle }">
|
<Section :is-opened="section.opened" :label="section.label">
|
||||||
<div class="sticky top-0 z-10 border-t bg-white p-3">
|
<SectionFields
|
||||||
<div
|
:fields="section.fields"
|
||||||
class="flex max-w-fit cursor-pointer items-center gap-2 px-2 text-base font-semibold leading-5"
|
v-model="lead.data"
|
||||||
@click="toggle()"
|
@update="updateField"
|
||||||
>
|
/>
|
||||||
<FeatherIcon
|
</Section>
|
||||||
name="chevron-right"
|
|
||||||
class="h-4 text-gray-600 transition-all duration-300 ease-in-out"
|
|
||||||
:class="{ 'rotate-90': opened }"
|
|
||||||
/>
|
|
||||||
{{ section.label }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<transition
|
|
||||||
enter-active-class="duration-300 ease-in"
|
|
||||||
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
|
||||||
enter-to-class="max-h-[200px] overflow-hidden"
|
|
||||||
leave-from-class="max-h-[200px] overflow-hidden"
|
|
||||||
enter-from-class="max-h-0 overflow-hidden"
|
|
||||||
leave-to-class="max-h-0 overflow-hidden"
|
|
||||||
>
|
|
||||||
<div v-if="opened" class="flex flex-col gap-1.5 px-3">
|
|
||||||
<SectionFields
|
|
||||||
:fields="section.fields"
|
|
||||||
v-model="lead.data"
|
|
||||||
@update="updateField"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</transition>
|
|
||||||
</Toggler>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -197,10 +174,10 @@ import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
|||||||
import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
||||||
import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
||||||
import LayoutHeader from '@/components/LayoutHeader.vue'
|
import LayoutHeader from '@/components/LayoutHeader.vue'
|
||||||
import Toggler from '@/components/Toggler.vue'
|
|
||||||
import Activities from '@/components/Activities.vue'
|
import Activities from '@/components/Activities.vue'
|
||||||
import UserAvatar from '@/components/UserAvatar.vue'
|
import UserAvatar from '@/components/UserAvatar.vue'
|
||||||
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
||||||
|
import Section from '@/components/Section.vue'
|
||||||
import SectionFields from '@/components/SectionFields.vue'
|
import SectionFields from '@/components/SectionFields.vue'
|
||||||
import {
|
import {
|
||||||
leadStatuses,
|
leadStatuses,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user