Merge pull request #511 from shariquerik/custom-actions-refactor
This commit is contained in:
commit
afb71fd759
@ -228,6 +228,9 @@ watch(iframeRef, (iframe) => {
|
|||||||
iframe.contentWindow.document.querySelector('.email-content')
|
iframe.contentWindow.document.querySelector('.email-content')
|
||||||
let parent = emailContent.closest('html')
|
let parent = emailContent.closest('html')
|
||||||
|
|
||||||
|
let theme = document.documentElement.getAttribute('data-theme')
|
||||||
|
parent.setAttribute('data-theme', theme)
|
||||||
|
|
||||||
iframe.style.height = parent.offsetHeight + 1 + 'px'
|
iframe.style.height = parent.offsetHeight + 1 + 'px'
|
||||||
|
|
||||||
let replyCollapsers = emailContent.querySelectorAll('.replyCollapser')
|
let replyCollapsers = emailContent.querySelectorAll('.replyCollapser')
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, h } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { Dropdown } from 'frappe-ui'
|
import { Dropdown } from 'frappe-ui'
|
||||||
import { isMobileView } from '@/composables/settings'
|
import { isMobileView } from '@/composables/settings'
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col items-center justify-center gap-4 rounded-lg border border-dashed min-h-64 text-ink-gray-5"
|
class="flex flex-col items-center justify-center gap-4 rounded-lg border border-dashed border-outline-gray-modals min-h-64 text-ink-gray-5"
|
||||||
@dragover.prevent="dragover"
|
@dragover.prevent="dragover"
|
||||||
@dragleave.prevent="dragleave"
|
@dragleave.prevent="dragleave"
|
||||||
@drop.prevent="dropfiles"
|
@drop.prevent="dropfiles"
|
||||||
@ -128,7 +128,7 @@ import FileAudioIcon from '@/components/Icons/FileAudioIcon.vue'
|
|||||||
import FileVideoIcon from '@/components/Icons/FileVideoIcon.vue'
|
import FileVideoIcon from '@/components/Icons/FileVideoIcon.vue'
|
||||||
import { createToast, formatDate, convertSize } from '@/utils'
|
import { createToast, formatDate, convertSize } from '@/utils'
|
||||||
import { FormControl, CircularProgressBar, createResource } from 'frappe-ui'
|
import { FormControl, CircularProgressBar, createResource } from 'frappe-ui'
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, watch, onUnmounted } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
doctype: {
|
doctype: {
|
||||||
@ -383,6 +383,12 @@ function fileIcon(type) {
|
|||||||
return FileTextIcon
|
return FileTextIcon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(showCamera, (value) => {
|
||||||
|
if (!value) stopStream()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => stopStream())
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
showFileBrowser,
|
showFileBrowser,
|
||||||
showWebLink,
|
showWebLink,
|
||||||
|
|||||||
@ -22,9 +22,7 @@
|
|||||||
size="sm"
|
size="sm"
|
||||||
class="hover:!bg-surface-gray-2"
|
class="hover:!bg-surface-gray-2"
|
||||||
>
|
>
|
||||||
<IndicatorIcon
|
<IndicatorIcon :class="parseColor(column.column.color)" />
|
||||||
:class="colorClasses(column.column.color, true)"
|
|
||||||
/>
|
|
||||||
</Button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ close }">
|
<template #body="{ close }">
|
||||||
@ -33,13 +31,12 @@
|
|||||||
>
|
>
|
||||||
<div class="flex gap-1">
|
<div class="flex gap-1">
|
||||||
<Button
|
<Button
|
||||||
:class="colorClasses(color)"
|
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
v-for="color in colors"
|
v-for="color in colors"
|
||||||
:key="color"
|
:key="color"
|
||||||
@click="() => (column.column.color = color)"
|
@click="() => (column.column.color = color)"
|
||||||
>
|
>
|
||||||
<IndicatorIcon />
|
<IndicatorIcon :class="parseColor(color)" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row-reverse">
|
<div class="flex flex-row-reverse">
|
||||||
@ -172,7 +169,7 @@
|
|||||||
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
|
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
|
||||||
import NestedPopover from '@/components/NestedPopover.vue'
|
import NestedPopover from '@/components/NestedPopover.vue'
|
||||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||||
import { isTouchScreenDevice } from '@/utils'
|
import { isTouchScreenDevice, colors, parseColor } from '@/utils'
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import { Dropdown } from 'frappe-ui'
|
import { Dropdown } from 'frappe-ui'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
@ -265,33 +262,4 @@ function updateColumn(d) {
|
|||||||
|
|
||||||
emit('update', data)
|
emit('update', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
function colorClasses(color, onlyIcon = false) {
|
|
||||||
let textColor = `!text-${color}-600`
|
|
||||||
if (color == 'black') {
|
|
||||||
textColor = '!text-ink-gray-9'
|
|
||||||
} else if (['gray', 'green'].includes(color)) {
|
|
||||||
textColor = `!text-${color}-700`
|
|
||||||
}
|
|
||||||
|
|
||||||
let bgColor = `!bg-${color}-100 hover:!bg-${color}-200 active:!bg-${color}-300`
|
|
||||||
|
|
||||||
return [textColor, onlyIcon ? '' : bgColor]
|
|
||||||
}
|
|
||||||
|
|
||||||
const colors = [
|
|
||||||
'gray',
|
|
||||||
'blue',
|
|
||||||
'green',
|
|
||||||
'red',
|
|
||||||
'pink',
|
|
||||||
'orange',
|
|
||||||
'amber',
|
|
||||||
'yellow',
|
|
||||||
'cyan',
|
|
||||||
'teal',
|
|
||||||
'violet',
|
|
||||||
'purple',
|
|
||||||
'black',
|
|
||||||
]
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -163,7 +163,7 @@ const tabs = createResource({
|
|||||||
if (field.fieldname == 'status') {
|
if (field.fieldname == 'status') {
|
||||||
field.fieldtype = 'Select'
|
field.fieldtype = 'Select'
|
||||||
field.options = dealStatuses.value
|
field.options = dealStatuses.value
|
||||||
field.prefix = getDealStatus(deal.status).iconColorClass
|
field.prefix = getDealStatus(deal.status).color
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.fieldtype === 'Table') {
|
if (field.fieldtype === 'Table') {
|
||||||
|
|||||||
@ -76,7 +76,7 @@ const tabs = createResource({
|
|||||||
if (field.fieldname == 'status') {
|
if (field.fieldname == 'status') {
|
||||||
field.fieldtype = 'Select'
|
field.fieldtype = 'Select'
|
||||||
field.options = leadStatuses.value
|
field.options = leadStatuses.value
|
||||||
field.prefix = getLeadStatus(lead.status).iconColorClass
|
field.prefix = getLeadStatus(lead.status).color
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field.fieldtype === 'Table') {
|
if (field.fieldtype === 'Table') {
|
||||||
|
|||||||
@ -582,7 +582,7 @@ function getDealRowObject(deal) {
|
|||||||
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
||||||
status: {
|
status: {
|
||||||
label: deal.status,
|
label: deal.status,
|
||||||
color: getDealStatus(deal.status)?.iconColorClass,
|
color: getDealStatus(deal.status)?.color,
|
||||||
},
|
},
|
||||||
email: deal.email,
|
email: deal.email,
|
||||||
mobile_no: deal.mobile_no,
|
mobile_no: deal.mobile_no,
|
||||||
|
|||||||
@ -8,20 +8,22 @@
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
</template>
|
</template>
|
||||||
<template #right-header>
|
<template #right-header>
|
||||||
<CustomActions v-if="customActions" :actions="customActions" />
|
<CustomActions
|
||||||
|
v-if="deal.data._customActions?.length"
|
||||||
|
:actions="deal.data._customActions"
|
||||||
|
/>
|
||||||
<AssignTo
|
<AssignTo
|
||||||
v-model="deal.data._assignedTo"
|
v-model="deal.data._assignedTo"
|
||||||
:data="deal.data"
|
:data="deal.data"
|
||||||
doctype="CRM Deal"
|
doctype="CRM Deal"
|
||||||
/>
|
/>
|
||||||
<Dropdown :options="statusOptions('deal', updateField, customStatuses)">
|
<Dropdown
|
||||||
|
:options="statusOptions('deal', updateField, deal.data._customStatuses)"
|
||||||
|
>
|
||||||
<template #default="{ open }">
|
<template #default="{ open }">
|
||||||
<Button
|
<Button :label="deal.data.status">
|
||||||
:label="deal.data.status"
|
|
||||||
:class="getDealStatus(deal.data.status).colorClass"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<IndicatorIcon />
|
<IndicatorIcon :class="getDealStatus(deal.data.status).color" />
|
||||||
</template>
|
</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
@ -317,14 +319,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const customActions = ref([])
|
|
||||||
const customStatuses = ref([])
|
|
||||||
|
|
||||||
const deal = createResource({
|
const deal = createResource({
|
||||||
url: 'crm.fcrm.doctype.crm_deal.api.get_deal',
|
url: 'crm.fcrm.doctype.crm_deal.api.get_deal',
|
||||||
params: { name: props.dealId },
|
params: { name: props.dealId },
|
||||||
cache: ['deal', props.dealId],
|
cache: ['deal', props.dealId],
|
||||||
onSuccess: async (data) => {
|
onSuccess: (data) => {
|
||||||
if (data.organization) {
|
if (data.organization) {
|
||||||
organization.update({
|
organization.update({
|
||||||
params: { doctype: 'CRM Organization', name: data.organization },
|
params: { doctype: 'CRM Organization', name: data.organization },
|
||||||
@ -332,7 +331,8 @@ const deal = createResource({
|
|||||||
organization.fetch()
|
organization.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj = {
|
setupAssignees(deal)
|
||||||
|
setupCustomizations(deal, {
|
||||||
doc: data,
|
doc: data,
|
||||||
$dialog,
|
$dialog,
|
||||||
$socket,
|
$socket,
|
||||||
@ -346,11 +346,7 @@ const deal = createResource({
|
|||||||
sections,
|
sections,
|
||||||
},
|
},
|
||||||
call,
|
call,
|
||||||
}
|
})
|
||||||
setupAssignees(data)
|
|
||||||
let customization = await setupCustomizations(data, obj)
|
|
||||||
customActions.value = customization.actions || []
|
|
||||||
customStatuses.value = customization.statuses || []
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -362,7 +362,7 @@ function getGroupedByRows(listRows, groupByField, columns) {
|
|||||||
if (groupByField.name == 'status') {
|
if (groupByField.name == 'status') {
|
||||||
groupDetail.icon = () =>
|
groupDetail.icon = () =>
|
||||||
h(IndicatorIcon, {
|
h(IndicatorIcon, {
|
||||||
class: getDealStatus(option)?.iconColorClass,
|
class: getDealStatus(option)?.color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
groupedRows.push(groupDetail)
|
groupedRows.push(groupDetail)
|
||||||
@ -421,7 +421,7 @@ function parseRows(rows, columns = []) {
|
|||||||
} else if (row == 'status') {
|
} else if (row == 'status') {
|
||||||
_rows[row] = {
|
_rows[row] = {
|
||||||
label: deal.status,
|
label: deal.status,
|
||||||
color: getDealStatus(deal.status)?.iconColorClass,
|
color: getDealStatus(deal.status)?.color,
|
||||||
}
|
}
|
||||||
} else if (row == 'sla_status') {
|
} else if (row == 'sla_status') {
|
||||||
let value = deal.sla_status
|
let value = deal.sla_status
|
||||||
|
|||||||
@ -8,20 +8,24 @@
|
|||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
</template>
|
</template>
|
||||||
<template #right-header>
|
<template #right-header>
|
||||||
<CustomActions v-if="customActions" :actions="customActions" />
|
<CustomActions
|
||||||
|
v-if="lead.data._customActions?.length"
|
||||||
|
:actions="lead.data._customActions"
|
||||||
|
/>
|
||||||
<AssignTo
|
<AssignTo
|
||||||
v-model="lead.data._assignedTo"
|
v-model="lead.data._assignedTo"
|
||||||
:data="lead.data"
|
:data="lead.data"
|
||||||
doctype="CRM Lead"
|
doctype="CRM Lead"
|
||||||
/>
|
/>
|
||||||
<Dropdown :options="statusOptions('lead', updateField, customStatuses)">
|
<Dropdown
|
||||||
|
:options="statusOptions('lead', updateField, lead.data._customStatuses)"
|
||||||
|
>
|
||||||
<template #default="{ open }">
|
<template #default="{ open }">
|
||||||
<Button
|
<Button :label="lead.data.status">
|
||||||
:label="lead.data.status"
|
|
||||||
:class="getLeadStatus(lead.data.status).colorClass"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<IndicatorIcon />
|
<IndicatorIcon
|
||||||
|
:class="getLeadStatus(lead.data.status).color"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
@ -329,15 +333,13 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const customActions = ref([])
|
|
||||||
const customStatuses = ref([])
|
|
||||||
|
|
||||||
const lead = createResource({
|
const lead = createResource({
|
||||||
url: 'crm.fcrm.doctype.crm_lead.api.get_lead',
|
url: 'crm.fcrm.doctype.crm_lead.api.get_lead',
|
||||||
params: { name: props.leadId },
|
params: { name: props.leadId },
|
||||||
cache: ['lead', props.leadId],
|
cache: ['lead', props.leadId],
|
||||||
onSuccess: async (data) => {
|
onSuccess: (data) => {
|
||||||
let obj = {
|
setupAssignees(lead)
|
||||||
|
setupCustomizations(lead, {
|
||||||
doc: data,
|
doc: data,
|
||||||
$dialog,
|
$dialog,
|
||||||
$socket,
|
$socket,
|
||||||
@ -345,16 +347,9 @@ const lead = createResource({
|
|||||||
updateField,
|
updateField,
|
||||||
createToast,
|
createToast,
|
||||||
deleteDoc: deleteLead,
|
deleteDoc: deleteLead,
|
||||||
resource: {
|
resource: { lead, sections },
|
||||||
lead,
|
|
||||||
sections,
|
|
||||||
},
|
|
||||||
call,
|
call,
|
||||||
}
|
})
|
||||||
setupAssignees(data)
|
|
||||||
let customization = await setupCustomizations(data, obj)
|
|
||||||
customActions.value = customization.actions || []
|
|
||||||
customStatuses.value = customization.statuses || []
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -382,7 +382,7 @@ function getGroupedByRows(listRows, groupByField, columns) {
|
|||||||
if (groupByField.name == 'status') {
|
if (groupByField.name == 'status') {
|
||||||
groupDetail.icon = () =>
|
groupDetail.icon = () =>
|
||||||
h(IndicatorIcon, {
|
h(IndicatorIcon, {
|
||||||
class: getLeadStatus(option)?.iconColorClass,
|
class: getLeadStatus(option)?.color,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
groupedRows.push(groupDetail)
|
groupedRows.push(groupDetail)
|
||||||
@ -444,7 +444,7 @@ function parseRows(rows, columns = []) {
|
|||||||
} else if (row == 'status') {
|
} else if (row == 'status') {
|
||||||
_rows[row] = {
|
_rows[row] = {
|
||||||
label: lead.status,
|
label: lead.status,
|
||||||
color: getLeadStatus(lead.status)?.iconColorClass,
|
color: getLeadStatus(lead.status)?.color,
|
||||||
}
|
}
|
||||||
} else if (row == 'sla_status') {
|
} else if (row == 'sla_status') {
|
||||||
let value = lead.sla_status
|
let value = lead.sla_status
|
||||||
|
|||||||
@ -592,7 +592,7 @@ function getDealRowObject(deal) {
|
|||||||
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
||||||
status: {
|
status: {
|
||||||
label: deal.status,
|
label: deal.status,
|
||||||
color: getDealStatus(deal.status)?.iconColorClass,
|
color: getDealStatus(deal.status)?.color,
|
||||||
},
|
},
|
||||||
email: deal.email,
|
email: deal.email,
|
||||||
mobile_no: deal.mobile_no,
|
mobile_no: deal.mobile_no,
|
||||||
|
|||||||
@ -9,14 +9,15 @@
|
|||||||
</template>
|
</template>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<div class="absolute right-0">
|
<div class="absolute right-0">
|
||||||
<Dropdown :options="statusOptions('deal', updateField, customStatuses)">
|
<Dropdown
|
||||||
|
:options="
|
||||||
|
statusOptions('deal', updateField, deal.data._customStatuses)
|
||||||
|
"
|
||||||
|
>
|
||||||
<template #default="{ open }">
|
<template #default="{ open }">
|
||||||
<Button
|
<Button :label="deal.data.status">
|
||||||
:label="deal.data.status"
|
|
||||||
:class="getDealStatus(deal.data.status).colorClass"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<IndicatorIcon />
|
<IndicatorIcon :class="getDealStatus(deal.data.status).color" />
|
||||||
</template>
|
</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
@ -40,7 +41,10 @@
|
|||||||
doctype="CRM Deal"
|
doctype="CRM Deal"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<CustomActions v-if="customActions" :actions="customActions" />
|
<CustomActions
|
||||||
|
v-if="deal.data._customActions?.length"
|
||||||
|
:actions="deal.data._customActions"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="deal.data" class="flex h-full overflow-hidden">
|
<div v-if="deal.data" class="flex h-full overflow-hidden">
|
||||||
@ -257,14 +261,11 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const customActions = ref([])
|
|
||||||
const customStatuses = ref([])
|
|
||||||
|
|
||||||
const deal = createResource({
|
const deal = createResource({
|
||||||
url: 'crm.fcrm.doctype.crm_deal.api.get_deal',
|
url: 'crm.fcrm.doctype.crm_deal.api.get_deal',
|
||||||
params: { name: props.dealId },
|
params: { name: props.dealId },
|
||||||
cache: ['deal', props.dealId],
|
cache: ['deal', props.dealId],
|
||||||
onSuccess: async (data) => {
|
onSuccess: (data) => {
|
||||||
if (data.organization) {
|
if (data.organization) {
|
||||||
organization.update({
|
organization.update({
|
||||||
params: { doctype: 'CRM Organization', name: data.organization },
|
params: { doctype: 'CRM Organization', name: data.organization },
|
||||||
@ -272,7 +273,8 @@ const deal = createResource({
|
|||||||
organization.fetch()
|
organization.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
let obj = {
|
setupAssignees(deal)
|
||||||
|
setupCustomizations(deal, {
|
||||||
doc: data,
|
doc: data,
|
||||||
$dialog,
|
$dialog,
|
||||||
$socket,
|
$socket,
|
||||||
@ -286,11 +288,7 @@ const deal = createResource({
|
|||||||
sections,
|
sections,
|
||||||
},
|
},
|
||||||
call,
|
call,
|
||||||
}
|
})
|
||||||
setupAssignees(data)
|
|
||||||
let customization = await setupCustomizations(data, obj)
|
|
||||||
customActions.value = customization.actions || []
|
|
||||||
customStatuses.value = customization.statuses || []
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -9,14 +9,15 @@
|
|||||||
</template>
|
</template>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
<div class="absolute right-0">
|
<div class="absolute right-0">
|
||||||
<Dropdown :options="statusOptions('lead', updateField, customStatuses)">
|
<Dropdown
|
||||||
|
:options="
|
||||||
|
statusOptions('lead', updateField, lead.data._customStatuses)
|
||||||
|
"
|
||||||
|
>
|
||||||
<template #default="{ open }">
|
<template #default="{ open }">
|
||||||
<Button
|
<Button :label="lead.data.status">
|
||||||
:label="lead.data.status"
|
|
||||||
:class="getLeadStatus(lead.data.status).colorClass"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<IndicatorIcon />
|
<IndicatorIcon :class="getLeadStatus(lead.data.status).color" />
|
||||||
</template>
|
</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
@ -40,7 +41,10 @@
|
|||||||
doctype="CRM Lead"
|
doctype="CRM Lead"
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<CustomActions v-if="customActions" :actions="customActions" />
|
<CustomActions
|
||||||
|
v-if="lead.data._customActions?.length"
|
||||||
|
:actions="lead.data._customActions"
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
:label="__('Convert')"
|
:label="__('Convert')"
|
||||||
variant="solid"
|
variant="solid"
|
||||||
@ -211,15 +215,13 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const customActions = ref([])
|
|
||||||
const customStatuses = ref([])
|
|
||||||
|
|
||||||
const lead = createResource({
|
const lead = createResource({
|
||||||
url: 'crm.fcrm.doctype.crm_lead.api.get_lead',
|
url: 'crm.fcrm.doctype.crm_lead.api.get_lead',
|
||||||
params: { name: props.leadId },
|
params: { name: props.leadId },
|
||||||
cache: ['lead', props.leadId],
|
cache: ['lead', props.leadId],
|
||||||
onSuccess: async (data) => {
|
onSuccess: (data) => {
|
||||||
let obj = {
|
setupAssignees(lead)
|
||||||
|
setupCustomizations(lead, {
|
||||||
doc: data,
|
doc: data,
|
||||||
$dialog,
|
$dialog,
|
||||||
$socket,
|
$socket,
|
||||||
@ -232,11 +234,7 @@ const lead = createResource({
|
|||||||
sections,
|
sections,
|
||||||
},
|
},
|
||||||
call,
|
call,
|
||||||
}
|
})
|
||||||
setupAssignees(data)
|
|
||||||
let customization = await setupCustomizations(data, obj)
|
|
||||||
customActions.value = customization.actions || []
|
|
||||||
customStatuses.value = customization.statuses || []
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -457,7 +457,7 @@ function getDealRowObject(deal) {
|
|||||||
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
||||||
status: {
|
status: {
|
||||||
label: deal.status,
|
label: deal.status,
|
||||||
color: getDealStatus(deal.status)?.iconColorClass,
|
color: getDealStatus(deal.status)?.color,
|
||||||
},
|
},
|
||||||
email: deal.email,
|
email: deal.email,
|
||||||
mobile_no: deal.mobile_no,
|
mobile_no: deal.mobile_no,
|
||||||
|
|||||||
@ -459,7 +459,7 @@ function getDealRowObject(deal) {
|
|||||||
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
annual_revenue: getFormattedCurrency('annual_revenue', deal),
|
||||||
status: {
|
status: {
|
||||||
label: deal.status,
|
label: deal.status,
|
||||||
color: getDealStatus(deal.status)?.iconColorClass,
|
color: getDealStatus(deal.status)?.color,
|
||||||
},
|
},
|
||||||
email: deal.email,
|
email: deal.email,
|
||||||
mobile_no: deal.mobile_no,
|
mobile_no: deal.mobile_no,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||||
import { capture } from '@/telemetry'
|
import { capture } from '@/telemetry'
|
||||||
|
import { parseColor } from '@/utils'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { createListResource } from 'frappe-ui'
|
import { createListResource } from 'frappe-ui'
|
||||||
import { reactive, h } from 'vue'
|
import { reactive, h } from 'vue'
|
||||||
@ -18,8 +19,7 @@ export const statusesStore = defineStore('crm-statuses', () => {
|
|||||||
auto: true,
|
auto: true,
|
||||||
transform(statuses) {
|
transform(statuses) {
|
||||||
for (let status of statuses) {
|
for (let status of statuses) {
|
||||||
status.colorClass = colorClasses(status.color)
|
status.color = parseColor(status.color)
|
||||||
status.iconColorClass = colorClasses(status.color, true)
|
|
||||||
leadStatusesByName[status.name] = status
|
leadStatusesByName[status.name] = status
|
||||||
}
|
}
|
||||||
return statuses
|
return statuses
|
||||||
@ -35,8 +35,7 @@ export const statusesStore = defineStore('crm-statuses', () => {
|
|||||||
auto: true,
|
auto: true,
|
||||||
transform(statuses) {
|
transform(statuses) {
|
||||||
for (let status of statuses) {
|
for (let status of statuses) {
|
||||||
status.colorClass = colorClasses(status.color)
|
status.color = parseColor(status.color)
|
||||||
status.iconColorClass = colorClasses(status.color, true)
|
|
||||||
dealStatusesByName[status.name] = status
|
dealStatusesByName[status.name] = status
|
||||||
}
|
}
|
||||||
return statuses
|
return statuses
|
||||||
@ -57,19 +56,6 @@ export const statusesStore = defineStore('crm-statuses', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
function colorClasses(color, onlyIcon = false) {
|
|
||||||
let textColor = `!text-${color}-600`
|
|
||||||
if (color == 'black') {
|
|
||||||
textColor = '!text-ink-gray-9'
|
|
||||||
} else if (['gray', 'green'].includes(color)) {
|
|
||||||
textColor = `!text-${color}-700`
|
|
||||||
}
|
|
||||||
|
|
||||||
let bgColor = `!bg-${color}-100 hover:!bg-${color}-200 active:!bg-${color}-300`
|
|
||||||
|
|
||||||
return [textColor, onlyIcon ? '' : bgColor]
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLeadStatus(name) {
|
function getLeadStatus(name) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
name = leadStatuses.data[0].name
|
name = leadStatuses.data[0].name
|
||||||
@ -107,10 +93,7 @@ export const statusesStore = defineStore('crm-statuses', () => {
|
|||||||
options.push({
|
options.push({
|
||||||
label: statusesByName[status]?.name,
|
label: statusesByName[status]?.name,
|
||||||
value: statusesByName[status]?.name,
|
value: statusesByName[status]?.name,
|
||||||
icon: () =>
|
icon: () => h(IndicatorIcon, { class: statusesByName[status]?.color }),
|
||||||
h(IndicatorIcon, {
|
|
||||||
class: statusesByName[status]?.iconColorClass,
|
|
||||||
}),
|
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
capture('status_changed', { doctype, status })
|
capture('status_changed', { doctype, status })
|
||||||
action && action('status', statusesByName[status]?.name)
|
action && action('status', statusesByName[status]?.name)
|
||||||
|
|||||||
@ -136,41 +136,41 @@ export function validateEmail(email) {
|
|||||||
return regExp.test(email)
|
return regExp.test(email)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setupAssignees(data) {
|
export function setupAssignees(doc) {
|
||||||
let { getUser } = usersStore()
|
let { getUser } = usersStore()
|
||||||
let assignees = data._assign || []
|
let assignees = doc.data?._assign || []
|
||||||
data._assignedTo = assignees.map((user) => ({
|
doc.data._assignedTo = assignees.map((user) => ({
|
||||||
name: user,
|
name: user,
|
||||||
image: getUser(user).user_image,
|
image: getUser(user).user_image,
|
||||||
label: getUser(user).full_name,
|
label: getUser(user).full_name,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFromScript(script, obj) {
|
async function getFormScript(script, obj) {
|
||||||
let scriptFn = new Function(script + '\nreturn setupForm')()
|
let scriptFn = new Function(script + '\nreturn setupForm')()
|
||||||
let formScript = await scriptFn(obj)
|
let formScript = await scriptFn(obj)
|
||||||
return formScript || {}
|
return formScript || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setupCustomizations(data, obj) {
|
export async function setupCustomizations(doc, obj) {
|
||||||
if (!data._form_script) return []
|
if (!doc.data?._form_script) return []
|
||||||
|
|
||||||
let statuses = []
|
let statuses = []
|
||||||
let actions = []
|
let actions = []
|
||||||
if (Array.isArray(data._form_script)) {
|
if (Array.isArray(doc.data._form_script)) {
|
||||||
for (let script of data._form_script) {
|
for (let script of doc.data._form_script) {
|
||||||
let _script = await getFromScript(script, obj)
|
let _script = await getFormScript(script, obj)
|
||||||
actions = actions.concat(_script?.actions || [])
|
actions = actions.concat(_script?.actions || [])
|
||||||
statuses = statuses.concat(_script?.statuses || [])
|
statuses = statuses.concat(_script?.statuses || [])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let _script = await getFromScript(data._form_script, obj)
|
let _script = await getFormScript(doc.data._form_script, obj)
|
||||||
actions = _script?.actions || []
|
actions = _script?.actions || []
|
||||||
statuses = _script?.statuses || []
|
statuses = _script?.statuses || []
|
||||||
}
|
}
|
||||||
|
|
||||||
data._customStatuses = statuses
|
doc.data._customStatuses = statuses
|
||||||
data._customActions = actions
|
doc.data._customActions = actions
|
||||||
return { statuses, actions }
|
return { statuses, actions }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +234,33 @@ export function copyToClipboard(text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const colors = [
|
||||||
|
'gray',
|
||||||
|
'blue',
|
||||||
|
'green',
|
||||||
|
'red',
|
||||||
|
'pink',
|
||||||
|
'orange',
|
||||||
|
'amber',
|
||||||
|
'yellow',
|
||||||
|
'cyan',
|
||||||
|
'teal',
|
||||||
|
'violet',
|
||||||
|
'purple',
|
||||||
|
'black',
|
||||||
|
]
|
||||||
|
|
||||||
|
export function parseColor(color) {
|
||||||
|
let textColor = `!text-${color}-600`
|
||||||
|
if (color == 'black') {
|
||||||
|
textColor = '!text-ink-gray-9'
|
||||||
|
} else if (['gray', 'green'].includes(color)) {
|
||||||
|
textColor = `!text-${color}-700`
|
||||||
|
}
|
||||||
|
|
||||||
|
return textColor
|
||||||
|
}
|
||||||
|
|
||||||
export function isEmoji(str) {
|
export function isEmoji(str) {
|
||||||
const emojiList = gemoji.map((emoji) => emoji.emoji)
|
const emojiList = gemoji.map((emoji) => emoji.emoji)
|
||||||
return emojiList.includes(str)
|
return emojiList.includes(str)
|
||||||
@ -306,7 +333,7 @@ export function isImage(extention) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRandom(len=4) {
|
export function getRandom(len = 4) {
|
||||||
let text = ''
|
let text = ''
|
||||||
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user