refactor: removed contact store from contact & contact modal
This commit is contained in:
parent
afb561110a
commit
95661987e8
@ -1,4 +1,5 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
|
||||
def validate(doc, method):
|
||||
@ -24,6 +25,31 @@ def set_primary_mobile_no(doc):
|
||||
doc.phone_nos[0].is_primary_mobile_no = 1
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_contact(name):
|
||||
Contact = frappe.qb.DocType("Contact")
|
||||
|
||||
query = (
|
||||
frappe.qb.from_(Contact)
|
||||
.select("*")
|
||||
.where(Contact.name == name)
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
contact = query.run(as_dict=True)
|
||||
if not len(contact):
|
||||
frappe.throw(_("Contact not found"), frappe.DoesNotExistError)
|
||||
contact = contact.pop()
|
||||
|
||||
contact["doctype"] = "Contact"
|
||||
contact["email_ids"] = frappe.get_all(
|
||||
"Contact Email", filters={"parent": name}, fields=["name", "email_id", "is_primary"]
|
||||
)
|
||||
contact["phone_nos"] = frappe.get_all(
|
||||
"Contact Phone", filters={"parent": name}, fields=["name", "phone", "is_primary_mobile_no"]
|
||||
)
|
||||
return contact
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_linked_deals(contact):
|
||||
"""Get linked deals for a contact"""
|
||||
|
||||
@ -40,10 +40,10 @@
|
||||
<template #default="{ open }">
|
||||
<Button
|
||||
variant="ghost"
|
||||
:label="contact[field.name]"
|
||||
:label="contact.data[field.name]"
|
||||
class="dropdown-button w-full justify-between truncate hover:bg-white"
|
||||
>
|
||||
<div class="truncate">{{ contact[field.name] }}</div>
|
||||
<div class="truncate">{{ contact.data[field.name] }}</div>
|
||||
<template #suffix>
|
||||
<FeatherIcon
|
||||
:name="open ? 'chevron-up' : 'chevron-down'"
|
||||
@ -166,7 +166,6 @@ import CertificateIcon from '@/components/Icons/CertificateIcon.vue'
|
||||
import EditIcon from '@/components/Icons/EditIcon.vue'
|
||||
import Link from '@/components/Controls/Link.vue'
|
||||
import Dropdown from '@/components/frappe-ui/Dropdown.vue'
|
||||
import { contactsStore } from '@/stores/contacts'
|
||||
import { call } from 'frappe-ui'
|
||||
import { ref, nextTick, watch, computed, h } from 'vue'
|
||||
import { createToast } from '@/utils'
|
||||
@ -189,7 +188,6 @@ const props = defineProps({
|
||||
|
||||
const router = useRouter()
|
||||
const show = defineModel()
|
||||
const { contacts } = contactsStore()
|
||||
|
||||
const detailMode = ref(false)
|
||||
const editMode = ref(false)
|
||||
@ -211,7 +209,7 @@ async function updateContact() {
|
||||
async function callSetValue(values) {
|
||||
const d = await call('frappe.client.set_value', {
|
||||
doctype: 'Contact',
|
||||
name: props.contact.name,
|
||||
name: props.contact.data.name,
|
||||
fieldname: values,
|
||||
})
|
||||
return d.name
|
||||
@ -238,7 +236,7 @@ async function callInsertDoc() {
|
||||
}
|
||||
|
||||
function handleContactUpdate(doc) {
|
||||
contacts.reload()
|
||||
props.contact.reload()
|
||||
if (doc.name && props.options.redirect) {
|
||||
router.push({
|
||||
name: 'Contact',
|
||||
@ -345,14 +343,14 @@ const sections = computed(() => {
|
||||
fields: [
|
||||
{
|
||||
label: 'Email',
|
||||
type: props.contact.name ? 'dropdown' : 'data',
|
||||
type: props.contact.data.name ? 'dropdown' : 'data',
|
||||
name: 'email_id',
|
||||
options:
|
||||
props.contact?.email_ids?.map((email) => {
|
||||
props.contact.data?.email_ids?.map((email) => {
|
||||
return {
|
||||
name: email.name,
|
||||
value: email.email_id,
|
||||
selected: email.email_id === props.contact.email_id,
|
||||
selected: email.email_id === props.contact.data.email_id,
|
||||
placeholder: 'john@doe.com',
|
||||
onClick: () => {
|
||||
_contact.value.email_id = email.email_id
|
||||
@ -366,7 +364,7 @@ const sections = computed(() => {
|
||||
}
|
||||
},
|
||||
onDelete: (option, isNew) => {
|
||||
props.contact.email_ids = props.contact.email_ids.filter(
|
||||
props.contact.data.email_ids = props.contact.data.email_ids.filter(
|
||||
(email) => email.name !== option.name
|
||||
)
|
||||
!isNew && deleteOption('Contact Email', option.name)
|
||||
@ -374,7 +372,7 @@ const sections = computed(() => {
|
||||
}
|
||||
}) || [],
|
||||
create: () => {
|
||||
props.contact?.email_ids?.push({
|
||||
props.contact.data?.email_ids?.push({
|
||||
name: 'new-1',
|
||||
value: '',
|
||||
selected: false,
|
||||
@ -388,14 +386,14 @@ const sections = computed(() => {
|
||||
fields: [
|
||||
{
|
||||
label: 'Mobile No.',
|
||||
type: props.contact.name ? 'dropdown' : 'data',
|
||||
type: props.contact.data.name ? 'dropdown' : 'data',
|
||||
name: 'actual_mobile_no',
|
||||
options:
|
||||
props.contact?.phone_nos?.map((phone) => {
|
||||
props.contact.data?.phone_nos?.map((phone) => {
|
||||
return {
|
||||
name: phone.name,
|
||||
value: phone.phone,
|
||||
selected: phone.phone === props.contact.actual_mobile_no,
|
||||
selected: phone.phone === props.contact.data.actual_mobile_no,
|
||||
placeholder: '+91 1234567890',
|
||||
onClick: () => {
|
||||
_contact.value.actual_mobile_no = phone.phone
|
||||
@ -410,7 +408,7 @@ const sections = computed(() => {
|
||||
}
|
||||
},
|
||||
onDelete: (option, isNew) => {
|
||||
props.contact.phone_nos = props.contact.phone_nos.filter(
|
||||
props.contact.data.phone_nos = props.contact.data.phone_nos.filter(
|
||||
(phone) => phone.name !== option.name
|
||||
)
|
||||
!isNew && deleteOption('Contact Phone', option.name)
|
||||
@ -418,7 +416,7 @@ const sections = computed(() => {
|
||||
}
|
||||
}) || [],
|
||||
create: () => {
|
||||
props.contact?.phone_nos?.push({
|
||||
props.contact.data?.phone_nos?.push({
|
||||
name: 'new-1',
|
||||
value: '',
|
||||
selected: false,
|
||||
@ -486,12 +484,12 @@ const sections = computed(() => {
|
||||
|
||||
async function setAsPrimary(field, value) {
|
||||
let d = await call('crm.api.contact.set_as_primary', {
|
||||
contact: props.contact.name,
|
||||
contact: props.contact.data.name,
|
||||
field,
|
||||
value,
|
||||
})
|
||||
if (d) {
|
||||
contacts.reload()
|
||||
props.contact.reload()
|
||||
createToast({
|
||||
title: 'Contact updated',
|
||||
icon: 'check',
|
||||
@ -502,12 +500,12 @@ async function setAsPrimary(field, value) {
|
||||
|
||||
async function createNew(field, value) {
|
||||
let d = await call('crm.api.contact.create_new', {
|
||||
contact: props.contact.name,
|
||||
contact: props.contact.data.name,
|
||||
field,
|
||||
value,
|
||||
})
|
||||
if (d) {
|
||||
contacts.reload()
|
||||
props.contact.reload()
|
||||
createToast({
|
||||
title: 'Contact updated',
|
||||
icon: 'check',
|
||||
@ -524,7 +522,7 @@ async function editOption(doctype, name, value) {
|
||||
value,
|
||||
})
|
||||
if (d) {
|
||||
contacts.reload()
|
||||
props.contact.reload()
|
||||
createToast({
|
||||
title: 'Contact updated',
|
||||
icon: 'check',
|
||||
@ -539,7 +537,7 @@ async function deleteOption(doctype, name) {
|
||||
name,
|
||||
})
|
||||
if (d) {
|
||||
contacts.reload()
|
||||
props.contact.reload()
|
||||
createToast({
|
||||
title: 'Contact updated',
|
||||
icon: 'check',
|
||||
@ -549,7 +547,7 @@ async function deleteOption(doctype, name) {
|
||||
}
|
||||
|
||||
const dirty = computed(() => {
|
||||
return JSON.stringify(props.contact) !== JSON.stringify(_contact.value)
|
||||
return JSON.stringify(props.contact.data) !== JSON.stringify(_contact.value)
|
||||
})
|
||||
|
||||
watch(
|
||||
@ -559,7 +557,7 @@ watch(
|
||||
detailMode.value = props.options.detailMode
|
||||
editMode.value = false
|
||||
nextTick(() => {
|
||||
_contact.value = { ...props.contact }
|
||||
_contact.value = { ...props.contact.data }
|
||||
if (_contact.value.name) {
|
||||
editMode.value = true
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<LayoutHeader v-if="contact">
|
||||
<LayoutHeader v-if="contact.data">
|
||||
<template #left-header>
|
||||
<Breadcrumbs :items="breadcrumbs" />
|
||||
</template>
|
||||
</LayoutHeader>
|
||||
<div class="flex h-full flex-col overflow-hidden">
|
||||
<div v-if="contact.data" class="flex h-full flex-col overflow-hidden">
|
||||
<FileUploader @success="changeContactImage" :validateFile="validateFile">
|
||||
<template #default="{ openFileSelector, error }">
|
||||
<div class="flex items-center justify-start gap-6 p-5">
|
||||
@ -12,18 +12,18 @@
|
||||
<Avatar
|
||||
size="3xl"
|
||||
class="h-24 w-24"
|
||||
:label="contact.full_name"
|
||||
:image="contact.image"
|
||||
:label="contact.data.full_name"
|
||||
:image="contact.data.image"
|
||||
/>
|
||||
<component
|
||||
:is="contact.image ? Dropdown : 'div'"
|
||||
:is="contact.data.image ? Dropdown : 'div'"
|
||||
v-bind="
|
||||
contact.image
|
||||
contact.data.image
|
||||
? {
|
||||
options: [
|
||||
{
|
||||
icon: 'upload',
|
||||
label: contact.image
|
||||
label: contact.data.image
|
||||
? 'Change image'
|
||||
: 'Upload image',
|
||||
onClick: openFileSelector,
|
||||
@ -51,62 +51,62 @@
|
||||
</component>
|
||||
</div>
|
||||
<div class="flex flex-col gap-0.5 truncate">
|
||||
<Tooltip :text="contact.full_name">
|
||||
<Tooltip :text="contact.data.full_name">
|
||||
<div class="truncate text-3xl font-semibold">
|
||||
<span v-if="contact.salutation">
|
||||
{{ contact.salutation + '. ' }}
|
||||
<span v-if="contact.data.salutation">
|
||||
{{ contact.data.salutation + '. ' }}
|
||||
</span>
|
||||
<span>{{ contact.full_name }}</span>
|
||||
<span>{{ contact.data.full_name }}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div class="flex items-center gap-2 text-base text-gray-700">
|
||||
<div v-if="contact.email_id" class="flex items-center gap-1.5">
|
||||
<div v-if="contact.data.email_id" class="flex items-center gap-1.5">
|
||||
<EmailIcon class="h-4 w-4" />
|
||||
<span class="">{{ contact.email_id }}</span>
|
||||
<span class="">{{ contact.data.email_id }}</span>
|
||||
</div>
|
||||
<span
|
||||
v-if="contact.email_id"
|
||||
v-if="contact.data.email_id"
|
||||
class="text-3xl leading-[0] text-gray-600"
|
||||
>
|
||||
·
|
||||
</span>
|
||||
<Tooltip text="Make Call" v-if="contact.actual_mobile_no">
|
||||
<Tooltip text="Make Call" v-if="contact.data.actual_mobile_no">
|
||||
<div
|
||||
class="flex cursor-pointer items-center gap-1.5"
|
||||
@click="makeCall(contact.actual_mobile_no)"
|
||||
@click="makeCall(contact.data.actual_mobile_no)"
|
||||
>
|
||||
<PhoneIcon class="h-4 w-4" />
|
||||
<span class="">{{ contact.actual_mobile_no }}</span>
|
||||
<span class="">{{ contact.data.actual_mobile_no }}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<span
|
||||
v-if="contact.actual_mobile_no"
|
||||
v-if="contact.data.actual_mobile_no"
|
||||
class="text-3xl leading-[0] text-gray-600"
|
||||
>
|
||||
·
|
||||
</span>
|
||||
<div
|
||||
v-if="contact.company_name"
|
||||
v-if="contact.data.company_name"
|
||||
class="flex items-center gap-1.5"
|
||||
>
|
||||
<Avatar
|
||||
size="xs"
|
||||
:label="contact.company_name"
|
||||
:label="contact.data.company_name"
|
||||
:image="
|
||||
getOrganization(contact.company_name)?.organization_logo
|
||||
getOrganization(contact.data.company_name)?.organization_logo
|
||||
"
|
||||
/>
|
||||
<span class="">{{ contact.company_name }}</span>
|
||||
<span class="">{{ contact.data.company_name }}</span>
|
||||
</div>
|
||||
<span
|
||||
v-if="contact.company_name"
|
||||
v-if="contact.data.company_name"
|
||||
class="text-3xl leading-[0] text-gray-600"
|
||||
>
|
||||
·
|
||||
</span>
|
||||
<Button
|
||||
v-if="
|
||||
contact.email_id || contact.mobile_no || contact.company_name
|
||||
contact.data.email_id || contact.data.mobile_no || contact.data.company_name
|
||||
"
|
||||
variant="ghost"
|
||||
label="More"
|
||||
@ -223,7 +223,6 @@ import {
|
||||
} from '@/utils'
|
||||
import { globalStore } from '@/stores/global.js'
|
||||
import { usersStore } from '@/stores/users.js'
|
||||
import { contactsStore } from '@/stores/contacts.js'
|
||||
import { organizationsStore } from '@/stores/organizations.js'
|
||||
import { statusesStore } from '@/stores/statuses'
|
||||
import { ref, computed, h } from 'vue'
|
||||
@ -231,7 +230,6 @@ import { useRouter } from 'vue-router'
|
||||
|
||||
const { $dialog, makeCall } = globalStore()
|
||||
|
||||
const { getContactByName, contacts } = contactsStore()
|
||||
const { getUser } = usersStore()
|
||||
const { getOrganization } = organizationsStore()
|
||||
const { getDealStatus } = statusesStore()
|
||||
@ -245,16 +243,14 @@ const props = defineProps({
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const contact = computed(() => getContactByName(props.contactId))
|
||||
|
||||
const showContactModal = ref(false)
|
||||
const detailMode = ref(false)
|
||||
|
||||
const breadcrumbs = computed(() => {
|
||||
let items = [{ label: 'Contacts', route: { name: 'Contacts' } }]
|
||||
items.push({
|
||||
label: contact.value.full_name,
|
||||
route: { name: 'Contact', params: { contactId: contact.value.name } },
|
||||
label: contact.data?.full_name,
|
||||
route: { name: 'Contact', params: { contactId: props.contactId } },
|
||||
})
|
||||
return items
|
||||
})
|
||||
@ -273,7 +269,7 @@ async function changeContactImage(file) {
|
||||
fieldname: 'image',
|
||||
value: file?.file_url || '',
|
||||
})
|
||||
contacts.reload()
|
||||
contact.reload()
|
||||
}
|
||||
|
||||
async function deleteContact() {
|
||||
@ -307,6 +303,22 @@ const tabs = [
|
||||
},
|
||||
]
|
||||
|
||||
const contact = createResource({
|
||||
url: 'crm.api.contact.get_contact',
|
||||
cache: ['contact', props.contactId],
|
||||
params: {
|
||||
name: props.contactId,
|
||||
},
|
||||
auto: true,
|
||||
transform: (data) => {
|
||||
return {
|
||||
...data,
|
||||
actual_mobile_no: data.mobile_no,
|
||||
mobile_no: data.mobile_no,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const deals = createResource({
|
||||
url: 'crm.api.contact.get_linked_deals',
|
||||
cache: ['deals', props.contactId],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user