refactor: removed contact store from contact & contact modal

This commit is contained in:
Shariq Ansari 2024-03-13 12:17:11 +05:30
parent afb561110a
commit 95661987e8
3 changed files with 91 additions and 55 deletions

View File

@ -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"""

View File

@ -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
}

View File

@ -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"
>
&middot;
</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"
>
&middot;
</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"
>
&middot;
</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],