refactor: organization modal

This commit is contained in:
Shariq Ansari 2024-03-18 15:02:23 +05:30
parent d6f8106cfb
commit 7b8a15d224
6 changed files with 63 additions and 66 deletions

View File

@ -115,9 +115,9 @@
v-for="action in dialogOptions.actions" v-for="action in dialogOptions.actions"
:key="action.label" :key="action.label"
v-bind="action" v-bind="action"
> :label="action.label"
{{ action.label }} :loading="loading"
</Button> />
</div> </div>
</div> </div>
</template> </template>
@ -130,16 +130,11 @@ import WebsiteIcon from '@/components/Icons/WebsiteIcon.vue'
import OrganizationsIcon from '@/components/Icons/OrganizationsIcon.vue' import OrganizationsIcon from '@/components/Icons/OrganizationsIcon.vue'
import TerritoryIcon from '@/components/Icons/TerritoryIcon.vue' import TerritoryIcon from '@/components/Icons/TerritoryIcon.vue'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import { organizationsStore } from '@/stores/organizations'
import { call, FeatherIcon } from 'frappe-ui' import { call, FeatherIcon } from 'frappe-ui'
import { ref, nextTick, watch, computed, h } from 'vue' import { ref, nextTick, watch, computed, h } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const props = defineProps({ const props = defineProps({
organization: {
type: Object,
default: {},
},
options: { options: {
type: Object, type: Object,
default: { default: {
@ -152,8 +147,9 @@ const props = defineProps({
const router = useRouter() const router = useRouter()
const show = defineModel() const show = defineModel()
const { organizations } = organizationsStore() const organization = defineModel('organization')
const loading = ref(false)
const title = ref(null) const title = ref(null)
const detailMode = ref(false) const detailMode = ref(false)
const editMode = ref(false) const editMode = ref(false)
@ -165,13 +161,15 @@ let _organization = ref({
industry: '', industry: '',
}) })
let doc = ref({})
async function updateOrganization() { async function updateOrganization() {
const old = { ...props.organization } const old = { ...doc.value }
const newOrg = { ..._organization.value } const newOrg = { ..._organization.value }
const nameChanged = old.name !== newOrg.name const nameChanged = old.organization_name !== newOrg.organization_name
delete old.name delete old.organization_name
delete newOrg.name delete newOrg.organization_name
const otherFieldChanged = JSON.stringify(old) !== JSON.stringify(newOrg) const otherFieldChanged = JSON.stringify(old) !== JSON.stringify(newOrg)
const values = newOrg const values = newOrg
@ -182,21 +180,23 @@ async function updateOrganization() {
} }
let name let name
loading.value = true
if (nameChanged) { if (nameChanged) {
name = await callRenameDoc() name = await callRenameDoc()
} }
if (otherFieldChanged) { if (otherFieldChanged) {
name = await callSetValue(values) name = await callSetValue(values)
} }
handleOrganizationUpdate({ name }) handleOrganizationUpdate({ name }, nameChanged)
} }
async function callRenameDoc() { async function callRenameDoc() {
const d = await call('frappe.client.rename_doc', { const d = await call('frappe.client.rename_doc', {
doctype: 'CRM Organization', doctype: 'CRM Organization',
old_name: props.organization.name, old_name: doc.value?.organization_name,
new_name: _organization.value.name, new_name: _organization.value.organization_name,
}) })
loading.value = false
return d return d
} }
@ -206,6 +206,7 @@ async function callSetValue(values) {
name: _organization.value.name, name: _organization.value.name,
fieldname: values, fieldname: values,
}) })
loading.value = false
return d.name return d.name
} }
@ -216,16 +217,18 @@ async function callInsertDoc() {
..._organization.value, ..._organization.value,
}, },
}) })
loading.value = false
doc.name && handleOrganizationUpdate(doc) doc.name && handleOrganizationUpdate(doc)
} }
function handleOrganizationUpdate(doc) { function handleOrganizationUpdate(doc, renamed = false) {
organizations.reload() if (doc.name && (props.options.redirect || renamed)) {
if (doc.name && props.options.redirect) {
router.push({ router.push({
name: 'Organization', name: 'Organization',
params: { organizationId: doc.name }, params: { organizationId: doc.name },
}) })
} else {
organization.value.reload?.()
} }
show.value = false show.value = false
props.options.afterInsert && props.options.afterInsert(doc) props.options.afterInsert && props.options.afterInsert(doc)
@ -296,7 +299,8 @@ watch(
nextTick(() => { nextTick(() => {
// TODO: Issue with FormControl // TODO: Issue with FormControl
// title.value.el.focus() // title.value.el.focus()
_organization.value = { ...props.organization } doc.value = organization.value?.doc || organization.value || {}
_organization.value = { ...doc.value }
if (_organization.value.name) { if (_organization.value.name) {
editMode.value = true editMode.value = true
} }

View File

@ -61,10 +61,10 @@
</div> </div>
<OrganizationModal <OrganizationModal
v-model="showOrganizationModal" v-model="showOrganizationModal"
:organization="_organization" v-model:organization="_organization"
:options="{ :options="{
redirect: false, redirect: false,
afterInsert: (doc) => (newLead.organization = doc.name), afterInsert: (doc) => (newDeal.organization = doc.name),
}" }"
/> />
</template> </template>

View File

@ -59,20 +59,11 @@
</div> </div>
</div> </div>
</div> </div>
<OrganizationModal
v-model="showOrganizationModal"
:organization="_organization"
:options="{
redirect: false,
afterInsert: (doc) => (newLead.organization = doc.name),
}"
/>
</template> </template>
<script setup> <script setup>
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue' import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
import UserAvatar from '@/components/UserAvatar.vue' import UserAvatar from '@/components/UserAvatar.vue'
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
import Link from '@/components/Controls/Link.vue' import Link from '@/components/Controls/Link.vue'
import { usersStore } from '@/stores/users' import { usersStore } from '@/stores/users'
import { statusesStore } from '@/stores/statuses' import { statusesStore } from '@/stores/statuses'
@ -89,9 +80,6 @@ const props = defineProps({
}, },
}) })
const showOrganizationModal = ref(false)
const _organization = ref({})
const allFields = computed(() => { const allFields = computed(() => {
return [ return [
{ {

View File

@ -260,7 +260,7 @@
</div> </div>
<OrganizationModal <OrganizationModal
v-model="showOrganizationModal" v-model="showOrganizationModal"
:organization="_organization" v-model:organization="_organization"
:options="{ :options="{
redirect: false, redirect: false,
afterInsert: (doc) => afterInsert: (doc) =>

View File

@ -1,10 +1,10 @@
<template> <template>
<LayoutHeader v-if="organization"> <LayoutHeader v-if="organization.doc">
<template #left-header> <template #left-header>
<Breadcrumbs :items="breadcrumbs" /> <Breadcrumbs :items="breadcrumbs" />
</template> </template>
</LayoutHeader> </LayoutHeader>
<div v-if="organization" class="flex flex-1 flex-col overflow-hidden"> <div v-if="organization.doc" class="flex flex-1 flex-col overflow-hidden">
<FileUploader <FileUploader
@success="changeOrganizationImage" @success="changeOrganizationImage"
:validateFile="validateFile" :validateFile="validateFile"
@ -14,19 +14,19 @@
<div class="group relative h-24 w-24"> <div class="group relative h-24 w-24">
<Avatar <Avatar
size="3xl" size="3xl"
:image="organization.organization_logo" :image="organization.doc.organization_logo"
:label="organization.name" :label="organization.doc.name"
class="!h-24 !w-24" class="!h-24 !w-24"
/> />
<component <component
:is="organization.organization_logo ? Dropdown : 'div'" :is="organization.doc.organization_logo ? Dropdown : 'div'"
v-bind=" v-bind="
organization.organization_logo organization.doc.organization_logo
? { ? {
options: [ options: [
{ {
icon: 'upload', icon: 'upload',
label: organization.organization_logo label: organization.doc.organization_logo
? 'Change image' ? 'Change image'
: 'Upload image', : 'Upload image',
onClick: openFileSelector, onClick: openFileSelector,
@ -55,67 +55,67 @@
</div> </div>
<div class="flex flex-col justify-center gap-0.5"> <div class="flex flex-col justify-center gap-0.5">
<div class="text-3xl font-semibold text-gray-900"> <div class="text-3xl font-semibold text-gray-900">
{{ organization.name }} {{ organization.doc.name }}
</div> </div>
<div class="flex items-center gap-2 text-base text-gray-700"> <div class="flex items-center gap-2 text-base text-gray-700">
<div <div
v-if="organization.website" v-if="organization.doc.website"
class="flex items-center gap-1.5" class="flex items-center gap-1.5"
> >
<WebsiteIcon class="h-4 w-4" /> <WebsiteIcon class="h-4 w-4" />
<span class="">{{ website(organization.website) }}</span> <span class="">{{ website(organization.doc.website) }}</span>
</div> </div>
<span <span
v-if="organization.website" v-if="organization.doc.website"
class="text-3xl leading-[0] text-gray-600" class="text-3xl leading-[0] text-gray-600"
> >
&middot; &middot;
</span> </span>
<div <div
v-if="organization.industry" v-if="organization.doc.industry"
class="flex items-center gap-1.5" class="flex items-center gap-1.5"
> >
<FeatherIcon name="briefcase" class="h-4 w-4" /> <FeatherIcon name="briefcase" class="h-4 w-4" />
<span class="">{{ organization.industry }}</span> <span class="">{{ organization.doc.industry }}</span>
</div> </div>
<span <span
v-if="organization.industry" v-if="organization.doc.industry"
class="text-3xl leading-[0] text-gray-600" class="text-3xl leading-[0] text-gray-600"
> >
&middot; &middot;
</span> </span>
<div <div
v-if="organization.territory" v-if="organization.doc.territory"
class="flex items-center gap-1.5" class="flex items-center gap-1.5"
> >
<TerritoryIcon class="h-4 w-4" /> <TerritoryIcon class="h-4 w-4" />
<span class="">{{ organization.territory }}</span> <span class="">{{ organization.doc.territory }}</span>
</div> </div>
<span <span
v-if="organization.territory" v-if="organization.doc.territory"
class="text-3xl leading-[0] text-gray-600" class="text-3xl leading-[0] text-gray-600"
> >
&middot; &middot;
</span> </span>
<div <div
v-if="organization.annual_revenue" v-if="organization.doc.annual_revenue"
class="flex items-center gap-1.5" class="flex items-center gap-1.5"
> >
<FeatherIcon name="dollar-sign" class="h-4 w-4" /> <FeatherIcon name="dollar-sign" class="h-4 w-4" />
<span class="">{{ organization.annual_revenue }}</span> <span class="">{{ organization.doc.annual_revenue }}</span>
</div> </div>
<span <span
v-if="organization.annual_revenue" v-if="organization.doc.annual_revenue"
class="text-3xl leading-[0] text-gray-600" class="text-3xl leading-[0] text-gray-600"
> >
&middot; &middot;
</span> </span>
<Button <Button
v-if=" v-if="
organization.website || organization.doc.website ||
organization.industry || organization.doc.industry ||
organization.territory || organization.doc.territory ||
organization.annual_revenue organization.doc.annual_revenue
" "
variant="ghost" variant="ghost"
label="More" label="More"
@ -191,7 +191,7 @@
v-if="tab.label === 'Contacts' && rows.length" v-if="tab.label === 'Contacts' && rows.length"
:rows="rows" :rows="rows"
:columns="columns" :columns="columns"
:options="{ selectable: false, showTooltip: false, }" :options="{ selectable: false, showTooltip: false }"
/> />
<div <div
v-if="!rows.length" v-if="!rows.length"
@ -207,7 +207,7 @@
</div> </div>
<OrganizationModal <OrganizationModal
v-model="showOrganizationModal" v-model="showOrganizationModal"
:organization="organization" v-model:organization="organization"
:options="{ detailMode }" :options="{ detailMode }"
/> />
</template> </template>
@ -221,6 +221,7 @@ import {
Tabs, Tabs,
call, call,
createListResource, createListResource,
createDocumentResource,
} from 'frappe-ui' } from 'frappe-ui'
import LayoutHeader from '@/components/LayoutHeader.vue' import LayoutHeader from '@/components/LayoutHeader.vue'
import OrganizationModal from '@/components/Modals/OrganizationModal.vue' import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
@ -234,7 +235,6 @@ import DealsIcon from '@/components/Icons/DealsIcon.vue'
import ContactsIcon from '@/components/Icons/ContactsIcon.vue' import ContactsIcon from '@/components/Icons/ContactsIcon.vue'
import { globalStore } from '@/stores/global' import { globalStore } from '@/stores/global'
import { usersStore } from '@/stores/users' import { usersStore } from '@/stores/users'
import { organizationsStore } from '@/stores/organizations.js'
import { statusesStore } from '@/stores/statuses' import { statusesStore } from '@/stores/statuses'
import { import {
dateFormat, dateFormat,
@ -253,14 +253,19 @@ const props = defineProps({
}) })
const { $dialog } = globalStore() const { $dialog } = globalStore()
const { organizations, getOrganization } = organizationsStore()
const { getDealStatus } = statusesStore() const { getDealStatus } = statusesStore()
const showOrganizationModal = ref(false) const showOrganizationModal = ref(false)
const detailMode = ref(false) const detailMode = ref(false)
const router = useRouter() const router = useRouter()
const organization = computed(() => getOrganization(props.organizationId)) const organization = createDocumentResource({
doctype: 'CRM Organization',
name: props.organizationId,
cache: ['organization', props.organizationId],
fields: ['*'],
auto: true,
})
const breadcrumbs = computed(() => { const breadcrumbs = computed(() => {
let items = [{ label: 'Organizations', route: { name: 'Organizations' } }] let items = [{ label: 'Organizations', route: { name: 'Organizations' } }]
@ -288,7 +293,7 @@ async function changeOrganizationImage(file) {
fieldname: 'organization_logo', fieldname: 'organization_logo',
value: file?.file_url || '', value: file?.file_url || '',
}) })
organizations.reload() organization.reload()
} }
async function deleteOrganization() { async function deleteOrganization() {

View File

@ -52,7 +52,7 @@
</Button> </Button>
</div> </div>
</div> </div>
<OrganizationModal v-model="showOrganizationModal" :organization="{}" /> <OrganizationModal v-model="showOrganizationModal" />
</template> </template>
<script setup> <script setup>
import OrganizationsIcon from '@/components/Icons/OrganizationsIcon.vue' import OrganizationsIcon from '@/components/Icons/OrganizationsIcon.vue'