refactor: update mobile lead/deal components

This commit is contained in:
Shariq Ansari 2025-07-30 17:31:22 +05:30
parent c38c190d42
commit 7e42599b49
4 changed files with 213 additions and 223 deletions

View File

@ -335,6 +335,7 @@
/> />
</template> </template>
<script setup> <script setup>
import DeleteLinkedDocModal from '@/components/DeleteLinkedDocModal.vue'
import ErrorPage from '@/components/ErrorPage.vue' import ErrorPage from '@/components/ErrorPage.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import Resizer from '@/components/Resizer.vue' import Resizer from '@/components/Resizer.vue'
@ -417,6 +418,7 @@ const props = defineProps({
const errorTitle = ref('') const errorTitle = ref('')
const errorMessage = ref('') const errorMessage = ref('')
const showDeleteLinkedDocModal = ref(false)
const { triggerOnChange, assignees, document, scripts, error } = useDocument( const { triggerOnChange, assignees, document, scripts, error } = useDocument(
'CRM Deal', 'CRM Deal',
@ -451,7 +453,7 @@ watch(
toast, toast,
updateField, updateField,
createToast: toast.create, createToast: toast.create,
deleteDoc: deleteDealWithModal, deleteDoc: deleteDeal,
call, call,
}) })
document._actions = s.actions || [] document._actions = s.actions || []
@ -493,7 +495,6 @@ const reload = ref(false)
const showOrganizationModal = ref(false) const showOrganizationModal = ref(false)
const showFilesUploader = ref(false) const showFilesUploader = ref(false)
const _organization = ref({}) const _organization = ref({})
const showDeleteLinkedDocModal = ref(false)
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
let items = [{ label: __('Deals'), route: { name: 'Deals' } }] let items = [{ label: __('Deals'), route: { name: 'Deals' } }]
@ -739,7 +740,7 @@ function updateField(name, value) {
}) })
} }
async function deleteDealWithModal() { function deleteDeal() {
showDeleteLinkedDocModal.value = true showDeleteLinkedDocModal.value = true
} }

View File

@ -183,7 +183,7 @@
<Tooltip :text="__('Delete')"> <Tooltip :text="__('Delete')">
<div> <div>
<Button <Button
@click="deleteLeadWithModal" @click="deleteLead"
variant="subtle" variant="subtle"
theme="red" theme="red"
icon="trash-2" icon="trash-2"
@ -245,6 +245,7 @@
/> />
</template> </template>
<script setup> <script setup>
import DeleteLinkedDocModal from '@/components/DeleteLinkedDocModal.vue'
import ErrorPage from '@/components/ErrorPage.vue' import ErrorPage from '@/components/ErrorPage.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import Resizer from '@/components/Resizer.vue' import Resizer from '@/components/Resizer.vue'
@ -294,7 +295,7 @@ import {
usePageMeta, usePageMeta,
toast, toast,
} from 'frappe-ui' } from 'frappe-ui'
import { ref, computed, onMounted, watch, nextTick } from 'vue' import { ref, computed, watch, nextTick } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { useActiveTabManager } from '@/composables/useActiveTabManager' import { useActiveTabManager } from '@/composables/useActiveTabManager'
@ -351,7 +352,7 @@ watch(
toast, toast,
updateField, updateField,
createToast: toast.create, createToast: toast.create,
deleteDoc: deleteLeadWithModal, deleteDoc: deleteLead,
call, call,
}) })
document._actions = s.actions || [] document._actions = s.actions || []
@ -501,7 +502,7 @@ function updateField(name, value) {
}) })
} }
async function deleteLeadWithModal() { function deleteLead() {
showDeleteLinkedDocModal.value = true showDeleteLinkedDocModal.value = true
} }

View File

@ -1,5 +1,5 @@
<template> <template>
<LayoutHeader v-if="deal.data"> <LayoutHeader>
<header <header
class="relative flex h-10.5 items-center justify-between gap-2 py-2.5 pl-2" class="relative flex h-10.5 items-center justify-between gap-2 py-2.5 pl-2"
> >
@ -10,23 +10,21 @@
</Breadcrumbs> </Breadcrumbs>
<div class="absolute right-0"> <div class="absolute right-0">
<Dropdown <Dropdown
v-if="document.doc" v-if="doc"
:options=" :options="
statusOptions( statusOptions(
'deal', 'deal',
document.statuses?.length document.statuses?.length
? document.statuses ? document.statuses
: deal.data._customStatuses, : document._statuses,
triggerStatusChange, triggerStatusChange,
) )
" "
> >
<template #default="{ open }"> <template #default="{ open }">
<Button :label="document.doc.status"> <Button v-if="doc.status" :label="doc.status">
<template #prefix> <template #prefix>
<IndicatorIcon <IndicatorIcon :class="getDealStatus(doc.status).color" />
:class="getDealStatus(document.doc.status).color"
/>
</template> </template>
<template #suffix> <template #suffix>
<FeatherIcon <FeatherIcon
@ -41,18 +39,14 @@
</header> </header>
</LayoutHeader> </LayoutHeader>
<div <div
v-if="deal.data" v-if="doc.name"
class="flex h-12 items-center justify-between gap-2 border-b px-3 py-2.5" class="flex h-12 items-center justify-between gap-2 border-b px-3 py-2.5"
> >
<AssignTo <AssignTo v-model="assignees.data" :data="doc" doctype="CRM Deal" />
v-model="assignees.data"
:data="document.doc"
doctype="CRM Deal"
/>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<CustomActions <CustomActions
v-if="deal.data._customActions?.length" v-if="document._actions?.length"
:actions="deal.data._customActions" :actions="document._actions"
/> />
<CustomActions <CustomActions
v-if="document.actions?.length" v-if="document.actions?.length"
@ -60,14 +54,14 @@
/> />
</div> </div>
</div> </div>
<div v-if="deal.data" class="flex h-full overflow-hidden"> <div v-if="doc.name" class="flex h-full overflow-hidden">
<Tabs as="div" v-model="tabIndex" :tabs="tabs" class="overflow-auto"> <Tabs as="div" v-model="tabIndex" :tabs="tabs" class="overflow-auto">
<TabList class="!px-3" /> <TabList class="!px-3" />
<TabPanel v-slot="{ tab }"> <TabPanel v-slot="{ tab }">
<div v-if="tab.name == 'Details'"> <div v-if="tab.name == 'Details'">
<SLASection <SLASection
v-if="deal.data.sla_status" v-if="doc.sla_status"
v-model="deal.data" v-model="doc"
@updateField="updateField" @updateField="updateField"
/> />
<div <div
@ -77,7 +71,7 @@
<SidePanelLayout <SidePanelLayout
:sections="sections.data" :sections="sections.data"
doctype="CRM Deal" doctype="CRM Deal"
:docname="deal.data.name" :docname="dealId"
@reload="sections.reload" @reload="sections.reload"
@beforeFieldChange="beforeStatusChange" @beforeFieldChange="beforeStatusChange"
@afterFieldChange="reloadAssignees" @afterFieldChange="reloadAssignees"
@ -92,7 +86,7 @@
(value, close) => { (value, close) => {
_contact = { _contact = {
first_name: value, first_name: value,
company_name: deal.data.organization, company_name: doc.organization,
} }
showContactModal = true showContactModal = true
close() close()
@ -220,23 +214,28 @@
<Activities <Activities
v-else v-else
doctype="CRM Deal" doctype="CRM Deal"
:docname="dealId"
:tabs="tabs" :tabs="tabs"
v-model:reload="reload" v-model:reload="reload"
v-model:tabIndex="tabIndex" v-model:tabIndex="tabIndex"
v-model="deal"
@beforeSave="beforeStatusChange" @beforeSave="beforeStatusChange"
@afterSave="reloadAssignees" @afterSave="reloadAssignees"
/> />
</TabPanel> </TabPanel>
</Tabs> </Tabs>
</div> </div>
<ErrorPage
v-else-if="errorTitle"
:errorTitle="errorTitle"
:errorMessage="errorMessage"
/>
<OrganizationModal <OrganizationModal
v-if="showOrganizationModal" v-if="showOrganizationModal"
v-model="showOrganizationModal" v-model="showOrganizationModal"
:data="_organization" :data="_organization"
:options="{ :options="{
redirect: false, redirect: false,
afterInsert: (doc) => updateField('organization', doc.name), afterInsert: (_doc) => updateField('organization', _doc.name),
}" }"
/> />
<ContactModal <ContactModal
@ -245,9 +244,16 @@
:contact="_contact" :contact="_contact"
:options="{ :options="{
redirect: false, redirect: false,
afterInsert: (doc) => addContact(doc.name), afterInsert: (_doc) => addContact(_doc.name),
}" }"
/> />
<DeleteLinkedDocModal
v-if="showDeleteLinkedDocModal"
v-model="showDeleteLinkedDocModal"
:doctype="'CRM Deal'"
:docname="dealId"
name="Deals"
/>
<LostReasonModal <LostReasonModal
v-if="showLostReasonModal" v-if="showLostReasonModal"
v-model="showLostReasonModal" v-model="showLostReasonModal"
@ -255,6 +261,8 @@
/> />
</template> </template>
<script setup> <script setup>
import DeleteLinkedDocModal from '@/components/DeleteLinkedDocModal.vue'
import ErrorPage from '@/components/ErrorPage.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import DetailsIcon from '@/components/Icons/DetailsIcon.vue' import DetailsIcon from '@/components/Icons/DetailsIcon.vue'
import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue' import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
@ -306,7 +314,7 @@ import {
usePageMeta, usePageMeta,
toast, toast,
} from 'frappe-ui' } from 'frappe-ui'
import { ref, computed, h, onMounted } from 'vue' import { ref, computed, h, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
const { brand } = getSettings() const { brand } = getSettings()
@ -323,86 +331,57 @@ const props = defineProps({
}, },
}) })
const deal = createResource({ const errorTitle = ref('')
url: 'crm.fcrm.doctype.crm_deal.api.get_deal', const errorMessage = ref('')
params: { name: props.dealId }, const showDeleteLinkedDocModal = ref(false)
cache: ['deal', props.dealId],
onSuccess: (data) => { const { triggerOnChange, assignees, document, scripts, error } = useDocument(
if (data.organization) { 'CRM Deal',
organization.update({ props.dealId,
params: { doctype: 'CRM Organization', name: data.organization }, )
const doc = computed(() => document.doc || {})
watch(error, (err) => {
if (err) {
errorTitle.value = __(
err.exc_type == 'DoesNotExistError'
? 'Document not found'
: 'Error occurred',
)
errorMessage.value = __(err.messages?.[0] || 'An error occurred')
} else {
errorTitle.value = ''
errorMessage.value = ''
}
})
watch(
() => document.doc,
async (_doc) => {
if (scripts.data?.length) {
let s = await setupCustomizations(scripts.data, {
doc: _doc,
$dialog,
$socket,
router,
toast,
updateField,
createToast: toast.create,
deleteDoc: deleteDeal,
call,
}) })
organization.fetch() document._actions = s.actions || []
document._statuses = s.statuses || []
} }
setupCustomizations(deal, {
doc: data,
$dialog,
$socket,
router,
toast,
updateField,
createToast: toast.create,
deleteDoc: deleteDeal,
resource: {
deal,
dealContacts,
sections,
},
call,
})
}, },
}) { once: true },
)
const organization = createResource({
url: 'frappe.client.get',
onSuccess: (data) => (deal.data._organizationObj = data),
})
onMounted(() => {
if (deal.data) return
deal.fetch()
})
const reload = ref(false) const reload = ref(false)
const showOrganizationModal = ref(false) const showOrganizationModal = ref(false)
const _organization = ref({}) const _organization = ref({})
function updateDeal(fieldname, value, callback) {
value = Array.isArray(fieldname) ? '' : value
if (validateRequired(fieldname, value)) return
createResource({
url: 'frappe.client.set_value',
params: {
doctype: 'CRM Deal',
name: props.dealId,
fieldname,
value,
},
auto: true,
onSuccess: () => {
deal.reload()
reload.value = true
toast.success(__('Deal updated'))
callback?.()
},
onError: (err) => {
toast.error(err.messages?.[0] || __('Error updating deal'))
},
})
}
function validateRequired(fieldname, value) {
let meta = deal.data.fields_meta || {}
if (meta[fieldname]?.reqd && !value) {
toast.error(__('{0} is a required field', [meta[fieldname].label]))
return true
}
return false
}
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
let items = [{ label: __('Deals'), route: { name: 'Deals' } }] let items = [{ label: __('Deals'), route: { name: 'Deals' } }]
@ -423,14 +402,14 @@ const breadcrumbs = computed(() => {
items.push({ items.push({
label: title.value, label: title.value,
route: { name: 'Deal', params: { dealId: deal.data.name } }, route: { name: 'Deal', params: { dealId: props.dealId } },
}) })
return items return items
}) })
const title = computed(() => { const title = computed(() => {
let t = doctypeMeta['CRM Deal']?.title_field || 'name' let t = doctypeMeta['CRM Deal']?.title_field || 'name'
return deal.data?.[t] || props.dealId return doc.value?.[t] || props.dealId
}) })
usePageMeta(() => { usePageMeta(() => {
@ -614,26 +593,33 @@ const dealContacts = createResource({
}, },
}) })
function updateField(name, value, callback) { function updateField(name, value) {
updateDeal(name, value, () => { value = Array.isArray(name) ? '' : value
deal.data[name] = value let oldValues = Array.isArray(name) ? {} : doc.value[name]
callback?.()
if (Array.isArray(name)) {
name.forEach((field) => (doc.value[field] = value))
} else {
doc.value[name] = value
}
document.save.submit(null, {
onSuccess: () => (reload.value = true),
onError: (err) => {
if (Array.isArray(name)) {
name.forEach((field) => (doc.value[field] = oldValues[field]))
} else {
doc.value[name] = oldValues
}
toast.error(err.messages?.[0] || __('Error updating field'))
},
}) })
} }
async function deleteDeal(name) { function deleteDeal() {
await call('frappe.client.delete', { showDeleteLinkedDocModal.value = true
doctype: 'CRM Deal',
name,
})
router.push({ name: 'Deals' })
} }
const { assignees, document, triggerOnChange } = useDocument(
'CRM Deal',
props.dealId,
)
async function triggerStatusChange(value) { async function triggerStatusChange(value) {
await triggerOnChange('status', value) await triggerOnChange('status', value)
setLostReason() setLostReason()
@ -643,9 +629,9 @@ const showLostReasonModal = ref(false)
function setLostReason() { function setLostReason() {
if ( if (
getDealStatus(document.doc.status).type !== 'Lost' || getDealStatus(doc.status).type !== 'Lost' ||
(document.doc.lost_reason && document.doc.lost_reason !== 'Other') || (doc.lost_reason && doc.lost_reason !== 'Other') ||
(document.doc.lost_reason === 'Other' && document.doc.lost_notes) (doc.lost_reason === 'Other' && doc.lost_notes)
) { ) {
document.save.submit() document.save.submit()
return return
@ -655,7 +641,10 @@ function setLostReason() {
} }
function beforeStatusChange(data) { function beforeStatusChange(data) {
if (data?.hasOwnProperty('status') && getDealStatus(data.status).type == 'Lost') { if (
data?.hasOwnProperty('status') &&
getDealStatus(data.status).type == 'Lost'
) {
setLostReason() setLostReason()
} else { } else {
document.save.submit(null, { document.save.submit(null, {

View File

@ -1,5 +1,5 @@
<template> <template>
<LayoutHeader v-if="lead.data"> <LayoutHeader>
<header <header
class="relative flex h-10.5 items-center justify-between gap-2 py-2.5 pl-2" class="relative flex h-10.5 items-center justify-between gap-2 py-2.5 pl-2"
> >
@ -10,23 +10,21 @@
</Breadcrumbs> </Breadcrumbs>
<div class="absolute right-0"> <div class="absolute right-0">
<Dropdown <Dropdown
v-if="document.doc" v-if="doc"
:options=" :options="
statusOptions( statusOptions(
'lead', 'lead',
document.statuses?.length document.statuses?.length
? document.statuses ? document.statuses
: lead.data._customStatuses, : document._statuses,
triggerStatusChange, triggerStatusChange,
) )
" "
> >
<template #default="{ open }"> <template #default="{ open }">
<Button :label="document.doc.status"> <Button v-if="doc.status" :label="doc.status">
<template #prefix> <template #prefix>
<IndicatorIcon <IndicatorIcon :class="getLeadStatus(doc.status).color" />
:class="getLeadStatus(document.doc.status).color"
/>
</template> </template>
<template #suffix> <template #suffix>
<FeatherIcon <FeatherIcon
@ -41,18 +39,14 @@
</header> </header>
</LayoutHeader> </LayoutHeader>
<div <div
v-if="lead.data" v-if="doc.name"
class="flex h-12 items-center justify-between gap-2 border-b px-3 py-2.5" class="flex h-12 items-center justify-between gap-2 border-b px-3 py-2.5"
> >
<AssignTo <AssignTo v-model="assignees.data" :data="doc" doctype="CRM Lead" />
v-model="assignees.data"
:data="document.doc"
doctype="CRM Lead"
/>
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<CustomActions <CustomActions
v-if="lead.data._customActions?.length" v-if="document._actions?.length"
:actions="lead.data._customActions" :actions="document._actions"
/> />
<CustomActions <CustomActions
v-if="document.actions?.length" v-if="document.actions?.length"
@ -65,14 +59,14 @@
/> />
</div> </div>
</div> </div>
<div v-if="lead?.data" class="flex h-full overflow-hidden"> <div v-if="doc.name" class="flex h-full overflow-hidden">
<Tabs as="div" v-model="tabIndex" :tabs="tabs" class="overflow-auto"> <Tabs as="div" v-model="tabIndex" :tabs="tabs" class="overflow-auto">
<TabList class="!px-3" /> <TabList class="!px-3" />
<TabPanel v-slot="{ tab }"> <TabPanel v-slot="{ tab }">
<div v-if="tab.name == 'Details'"> <div v-if="tab.name == 'Details'">
<SLASection <SLASection
v-if="lead.data.sla_status" v-if="doc.sla_status"
v-model="lead.data" v-model="doc"
@updateField="updateField" @updateField="updateField"
/> />
<div <div
@ -82,7 +76,7 @@
<SidePanelLayout <SidePanelLayout
:sections="sections.data" :sections="sections.data"
doctype="CRM Lead" doctype="CRM Lead"
:docname="lead.data.name" :docname="leadId"
@reload="sections.reload" @reload="sections.reload"
@afterFieldChange="reloadAssignees" @afterFieldChange="reloadAssignees"
/> />
@ -91,16 +85,21 @@
<Activities <Activities
v-else v-else
doctype="CRM Lead" doctype="CRM Lead"
:docname="leadId"
:tabs="tabs" :tabs="tabs"
v-model:reload="reload" v-model:reload="reload"
v-model:tabIndex="tabIndex" v-model:tabIndex="tabIndex"
v-model="lead"
@beforeSave="saveChanges" @beforeSave="saveChanges"
@afterSave="reloadAssignees" @afterSave="reloadAssignees"
/> />
</TabPanel> </TabPanel>
</Tabs> </Tabs>
</div> </div>
<ErrorPage
v-else-if="errorTitle"
:errorTitle="errorTitle"
:errorMessage="errorMessage"
/>
<Dialog <Dialog
v-model="showConvertToDealModal" v-model="showConvertToDealModal"
:options="{ :options="{
@ -167,8 +166,17 @@
</div> </div>
</template> </template>
</Dialog> </Dialog>
<DeleteLinkedDocModal
v-if="showDeleteLinkedDocModal"
v-model="showDeleteLinkedDocModal"
:doctype="'CRM Lead'"
:docname="leadId"
name="Leads"
/>
</template> </template>
<script setup> <script setup>
import DeleteLinkedDocModal from '@/components/DeleteLinkedDocModal.vue'
import ErrorPage from '@/components/ErrorPage.vue'
import Icon from '@/components/Icon.vue' import Icon from '@/components/Icon.vue'
import DetailsIcon from '@/components/Icons/DetailsIcon.vue' import DetailsIcon from '@/components/Icons/DetailsIcon.vue'
import ActivityIcon from '@/components/Icons/ActivityIcon.vue' import ActivityIcon from '@/components/Icons/ActivityIcon.vue'
@ -215,7 +223,7 @@ import {
usePageMeta, usePageMeta,
toast, toast,
} from 'frappe-ui' } from 'frappe-ui'
import { ref, computed, onMounted, watch } from 'vue' import { ref, computed, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
const { brand } = getSettings() const { brand } = getSettings()
@ -232,71 +240,55 @@ const props = defineProps({
}, },
}) })
const lead = createResource({ const errorTitle = ref('')
url: 'crm.fcrm.doctype.crm_lead.api.get_lead', const errorMessage = ref('')
params: { name: props.leadId }, const showDeleteLinkedDocModal = ref(false)
cache: ['lead', props.leadId],
onSuccess: (data) => { const { triggerOnChange, assignees, document, scripts, error } = useDocument(
setupCustomizations(lead, { 'CRM Lead',
doc: data, props.leadId,
$dialog, )
$socket,
router, const doc = computed(() => document.doc || {})
toast,
updateField, watch(error, (err) => {
createToast: toast.create, if (err) {
deleteDoc: deleteLead, errorTitle.value = __(
resource: { err.exc_type == 'DoesNotExistError'
lead, ? 'Document not found'
sections, : 'Error occurred',
}, )
call, errorMessage.value = __(err.messages?.[0] || 'An error occurred')
}) } else {
}, errorTitle.value = ''
errorMessage.value = ''
}
}) })
onMounted(() => { watch(
if (lead.data) return () => document.doc,
lead.fetch() async (_doc) => {
}) if (scripts.data?.length) {
let s = await setupCustomizations(scripts.data, {
doc: _doc,
$dialog,
$socket,
router,
toast,
updateField,
createToast: toast.create,
deleteDoc: deleteLead,
call,
})
document._actions = s.actions || []
document._statuses = s.statuses || []
}
},
{ once: true },
)
const reload = ref(false) const reload = ref(false)
function updateLead(fieldname, value, callback) {
value = Array.isArray(fieldname) ? '' : value
if (!Array.isArray(fieldname) && validateRequired(fieldname, value)) return
createResource({
url: 'frappe.client.set_value',
params: {
doctype: 'CRM Lead',
name: props.leadId,
fieldname,
value,
},
auto: true,
onSuccess: () => {
lead.reload()
reload.value = true
toast.success(__('Lead updated successfully'))
callback?.()
},
onError: (err) => {
toast.error(__(err.messages?.[0] || 'Error updating lead'))
},
})
}
function validateRequired(fieldname, value) {
let meta = lead.data.fields_meta || {}
if (meta[fieldname]?.reqd && !value) {
toast.error(__('{0} is a required field', [meta[fieldname].label]))
return true
}
return false
}
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
let items = [{ label: __('Leads'), route: { name: 'Leads' } }] let items = [{ label: __('Leads'), route: { name: 'Leads' } }]
@ -317,14 +309,14 @@ const breadcrumbs = computed(() => {
items.push({ items.push({
label: title.value, label: title.value,
route: { name: 'Lead', params: { leadId: lead.data.name } }, route: { name: 'Lead', params: { leadId: props.leadId } },
}) })
return items return items
}) })
const title = computed(() => { const title = computed(() => {
let t = doctypeMeta['CRM Lead']?.title_field || 'name' let t = doctypeMeta['CRM Lead']?.title_field || 'name'
return lead.data?.[t] || props.leadId return doc.value?.[t] || props.leadId
}) })
usePageMeta(() => { usePageMeta(() => {
@ -412,19 +404,31 @@ const sections = createResource({
auto: true, auto: true,
}) })
function updateField(name, value, callback) { function updateField(name, value) {
updateLead(name, value, () => { value = Array.isArray(name) ? '' : value
lead.data[name] = value let oldValues = Array.isArray(name) ? {} : doc.value[name]
callback?.()
if (Array.isArray(name)) {
name.forEach((field) => (doc.value[field] = value))
} else {
doc.value[name] = value
}
document.save.submit(null, {
onSuccess: () => (reload.value = true),
onError: (err) => {
if (Array.isArray(name)) {
name.forEach((field) => (doc.value[field] = oldValues[field]))
} else {
doc.value[name] = oldValues
}
toast.error(err.messages?.[0] || __('Error updating field'))
},
}) })
} }
async function deleteLead(name) { function deleteLead() {
await call('frappe.client.delete', { showDeleteLinkedDocModal.value = true
doctype: 'CRM Lead',
name,
})
router.push({ name: 'Leads' })
} }
// Convert to Deal // Convert to Deal
@ -455,7 +459,7 @@ async function convertToDeal() {
} }
let deal = await call('crm.fcrm.doctype.crm_lead.crm_lead.convert_to_deal', { let deal = await call('crm.fcrm.doctype.crm_lead.crm_lead.convert_to_deal', {
lead: lead.data.name, lead: props.leadId,
deal: {}, deal: {},
existing_contact: existingContact.value, existing_contact: existingContact.value,
existing_organization: existingOrganization.value, existing_organization: existingOrganization.value,
@ -471,11 +475,6 @@ async function convertToDeal() {
} }
} }
const { assignees, document, triggerOnChange } = useDocument(
'CRM Lead',
props.leadId,
)
async function triggerStatusChange(value) { async function triggerStatusChange(value) {
await triggerOnChange('status', value) await triggerOnChange('status', value)
document.save.submit() document.save.submit()