fix: created Section Component using Toggler component and used in lead/deal
This commit is contained in:
parent
36455b8faf
commit
b157f255f8
56
frontend/src/components/Section.vue
Normal file
56
frontend/src/components/Section.vue
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<slot name="header" v-bind="{ opened, open, close, toggle }">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div
|
||||||
|
class="flex h-7 max-w-fit cursor-pointer items-center gap-2 pl-2 pr-3 text-base font-semibold leading-5"
|
||||||
|
@click="toggle()"
|
||||||
|
>
|
||||||
|
<FeatherIcon
|
||||||
|
name="chevron-right"
|
||||||
|
class="h-4 text-gray-900 transition-all duration-300 ease-in-out"
|
||||||
|
:class="{ 'rotate-90': opened }"
|
||||||
|
/>
|
||||||
|
{{ label || 'Untitled' }}
|
||||||
|
</div>
|
||||||
|
<slot name="actions"></slot>
|
||||||
|
</div>
|
||||||
|
</slot>
|
||||||
|
<transition
|
||||||
|
enter-active-class="duration-300 ease-in"
|
||||||
|
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
||||||
|
enter-to-class="max-h-[200px] overflow-hidden"
|
||||||
|
leave-from-class="max-h-[200px] overflow-hidden"
|
||||||
|
enter-from-class="max-h-0 overflow-hidden"
|
||||||
|
leave-to-class="max-h-0 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div v-if="opened">
|
||||||
|
<slot v-bind="{ opened, open, close, toggle }" />
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { FeatherIcon } from 'frappe-ui'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
const props = defineProps({
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
isOpened: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
function toggle() {
|
||||||
|
opened.value = !opened.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
opened.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
opened.value = false
|
||||||
|
}
|
||||||
|
let opened = ref(props.isOpened)
|
||||||
|
</script>
|
||||||
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<div class="flex flex-col gap-1.5">
|
||||||
<div
|
<div
|
||||||
v-for="field in fields"
|
v-for="field in fields"
|
||||||
:key="field.label"
|
:key="field.label"
|
||||||
@ -65,6 +66,7 @@
|
|||||||
@click="field.link(data[field.name])"
|
@click="field.link(data[field.name])"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
<template>
|
|
||||||
<slot v-bind="{ opened, open, close, toggle }"></slot>
|
|
||||||
</template>
|
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
const props = defineProps({
|
|
||||||
isOpened: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
function toggle() {
|
|
||||||
opened.value = !opened.value
|
|
||||||
}
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
opened.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
opened.value = false
|
|
||||||
}
|
|
||||||
let opened = ref(props.isOpened)
|
|
||||||
</script>
|
|
||||||
@ -101,19 +101,8 @@
|
|||||||
class="flex flex-col p-3"
|
class="flex flex-col p-3"
|
||||||
:class="{ 'border-b': i !== detailSections.data.length - 1 }"
|
:class="{ 'border-b': i !== detailSections.data.length - 1 }"
|
||||||
>
|
>
|
||||||
<Toggler :is-opened="section.opened" v-slot="{ opened, toggle }">
|
<Section :is-opened="section.opened" :label="section.label">
|
||||||
<div class="flex items-center justify-between">
|
<template #actions>
|
||||||
<div
|
|
||||||
class="flex h-7 max-w-fit cursor-pointer items-center gap-2 pl-2 pr-3 text-base font-semibold leading-5"
|
|
||||||
@click="toggle()"
|
|
||||||
>
|
|
||||||
<FeatherIcon
|
|
||||||
name="chevron-right"
|
|
||||||
class="h-4 text-gray-900 transition-all duration-300 ease-in-out"
|
|
||||||
:class="{ 'rotate-90': opened }"
|
|
||||||
/>
|
|
||||||
{{ section.label }}
|
|
||||||
</div>
|
|
||||||
<div v-if="section.contacts" class="pr-2">
|
<div v-if="section.contacts" class="pr-2">
|
||||||
<Link
|
<Link
|
||||||
value=""
|
value=""
|
||||||
@ -143,16 +132,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
<transition
|
|
||||||
enter-active-class="duration-300 ease-in"
|
|
||||||
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
|
||||||
enter-to-class="max-h-[200px] overflow-hidden"
|
|
||||||
leave-from-class="max-h-[200px] overflow-hidden"
|
|
||||||
enter-from-class="max-h-0 overflow-hidden"
|
|
||||||
leave-to-class="max-h-0 overflow-hidden"
|
|
||||||
>
|
|
||||||
<div v-if="opened" class="flex flex-col gap-1.5">
|
|
||||||
<SectionFields
|
<SectionFields
|
||||||
v-if="section.fields"
|
v-if="section.fields"
|
||||||
:fields="section.fields"
|
:fields="section.fields"
|
||||||
@ -169,21 +149,17 @@
|
|||||||
class="px-2 pb-2.5"
|
class="px-2 pb-2.5"
|
||||||
:class="[i == 0 ? 'pt-5' : 'pt-2.5']"
|
:class="[i == 0 ? 'pt-5' : 'pt-2.5']"
|
||||||
>
|
>
|
||||||
<Toggler
|
<Section :is-opened="contact.opened">
|
||||||
:is-opened="contact.opened"
|
<template #header="{ opened, toggle }">
|
||||||
v-slot="{ opened: cOpened, toggle: cToggle }"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="flex cursor-pointer items-center justify-between gap-2 pr-1 text-base leading-5 text-gray-700"
|
class="flex cursor-pointer items-center justify-between gap-2 pr-1 text-base leading-5 text-gray-700"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex h-7 items-center gap-2"
|
class="flex h-7 items-center gap-2"
|
||||||
@click="cToggle()"
|
@click="toggle()"
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
:label="
|
:label="getContactByName(contact.name).full_name"
|
||||||
getContactByName(contact.name).full_name
|
|
||||||
"
|
|
||||||
:image="getContactByName(contact.name).image"
|
:image="getContactByName(contact.name).image"
|
||||||
size="md"
|
size="md"
|
||||||
/>
|
/>
|
||||||
@ -216,30 +192,20 @@
|
|||||||
>
|
>
|
||||||
<ExternalLinkIcon class="h-4 w-4" />
|
<ExternalLinkIcon class="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="ghost" @click="cToggle()">
|
<Button variant="ghost" @click="toggle()">
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
name="chevron-right"
|
name="chevron-right"
|
||||||
class="h-4 w-4 text-gray-900 transition-all duration-300 ease-in-out"
|
class="h-4 w-4 text-gray-900 transition-all duration-300 ease-in-out"
|
||||||
:class="{ 'rotate-90': cOpened }"
|
:class="{ 'rotate-90': opened }"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition
|
</template>
|
||||||
enter-active-class="duration-300 ease-in"
|
|
||||||
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
|
||||||
enter-to-class="max-h-[200px] overflow-hidden"
|
|
||||||
leave-from-class="max-h-[200px] overflow-hidden"
|
|
||||||
enter-from-class="max-h-0 overflow-hidden"
|
|
||||||
leave-to-class="max-h-0 overflow-hidden"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-if="cOpened"
|
|
||||||
class="flex flex-col gap-1.5 text-base text-gray-800"
|
class="flex flex-col gap-1.5 text-base text-gray-800"
|
||||||
>
|
>
|
||||||
<div
|
<div class="flex items-center gap-3 pb-1.5 pl-1 pt-4">
|
||||||
class="flex items-center gap-3 pb-1.5 pl-1 pt-4"
|
|
||||||
>
|
|
||||||
<EmailIcon class="h-4 w-4" />
|
<EmailIcon class="h-4 w-4" />
|
||||||
{{ getContactByName(contact.name).email_id }}
|
{{ getContactByName(contact.name).email_id }}
|
||||||
</div>
|
</div>
|
||||||
@ -248,8 +214,7 @@
|
|||||||
{{ getContactByName(contact.name).mobile_no }}
|
{{ getContactByName(contact.name).mobile_no }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</Section>
|
||||||
</Toggler>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="i != section.contacts.length - 1"
|
v-if="i != section.contacts.length - 1"
|
||||||
@ -263,9 +228,7 @@
|
|||||||
No contacts added
|
No contacts added
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Section>
|
||||||
</transition>
|
|
||||||
</Toggler>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -302,12 +265,12 @@ import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
|||||||
import ExternalLinkIcon from '@/components/Icons/ExternalLinkIcon.vue'
|
import ExternalLinkIcon from '@/components/Icons/ExternalLinkIcon.vue'
|
||||||
import SuccessIcon from '@/components/Icons/SuccessIcon.vue'
|
import SuccessIcon from '@/components/Icons/SuccessIcon.vue'
|
||||||
import LayoutHeader from '@/components/LayoutHeader.vue'
|
import LayoutHeader from '@/components/LayoutHeader.vue'
|
||||||
import Toggler from '@/components/Toggler.vue'
|
|
||||||
import Activities from '@/components/Activities.vue'
|
import Activities from '@/components/Activities.vue'
|
||||||
import UserAvatar from '@/components/UserAvatar.vue'
|
import UserAvatar from '@/components/UserAvatar.vue'
|
||||||
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
||||||
import ContactModal from '@/components/Modals/ContactModal.vue'
|
import ContactModal from '@/components/Modals/ContactModal.vue'
|
||||||
import Link from '@/components/Controls/Link.vue'
|
import Link from '@/components/Controls/Link.vue'
|
||||||
|
import Section from '@/components/Section.vue'
|
||||||
import SectionFields from '@/components/SectionFields.vue'
|
import SectionFields from '@/components/SectionFields.vue'
|
||||||
import {
|
import {
|
||||||
dealStatuses,
|
dealStatuses,
|
||||||
|
|||||||
@ -57,7 +57,7 @@
|
|||||||
:validateFile="validateFile"
|
:validateFile="validateFile"
|
||||||
>
|
>
|
||||||
<template #default="{ openFileSelector, error }">
|
<template #default="{ openFileSelector, error }">
|
||||||
<div class="flex items-center justify-start gap-5 p-5">
|
<div class="flex items-center justify-start gap-5 border-b p-5">
|
||||||
<div class="group relative h-[88px] w-[88px]">
|
<div class="group relative h-[88px] w-[88px]">
|
||||||
<Avatar
|
<Avatar
|
||||||
size="3xl"
|
size="3xl"
|
||||||
@ -135,41 +135,18 @@
|
|||||||
<div class="flex flex-1 flex-col justify-between overflow-hidden">
|
<div class="flex flex-1 flex-col justify-between overflow-hidden">
|
||||||
<div class="flex flex-col overflow-y-auto">
|
<div class="flex flex-col overflow-y-auto">
|
||||||
<div
|
<div
|
||||||
v-for="section in detailSections.data"
|
v-for="(section, i) in detailSections.data"
|
||||||
:key="section.label"
|
:key="section.label"
|
||||||
class="flex flex-col"
|
class="flex flex-col p-3"
|
||||||
|
:class="{ 'border-b': i !== detailSections.data.length - 1 }"
|
||||||
>
|
>
|
||||||
<Toggler :is-opened="section.opened" v-slot="{ opened, toggle }">
|
<Section :is-opened="section.opened" :label="section.label">
|
||||||
<div class="sticky top-0 z-10 border-t bg-white p-3">
|
|
||||||
<div
|
|
||||||
class="flex max-w-fit cursor-pointer items-center gap-2 px-2 text-base font-semibold leading-5"
|
|
||||||
@click="toggle()"
|
|
||||||
>
|
|
||||||
<FeatherIcon
|
|
||||||
name="chevron-right"
|
|
||||||
class="h-4 text-gray-600 transition-all duration-300 ease-in-out"
|
|
||||||
:class="{ 'rotate-90': opened }"
|
|
||||||
/>
|
|
||||||
{{ section.label }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<transition
|
|
||||||
enter-active-class="duration-300 ease-in"
|
|
||||||
leave-active-class="duration-300 ease-[cubic-bezier(0, 1, 0.5, 1)]"
|
|
||||||
enter-to-class="max-h-[200px] overflow-hidden"
|
|
||||||
leave-from-class="max-h-[200px] overflow-hidden"
|
|
||||||
enter-from-class="max-h-0 overflow-hidden"
|
|
||||||
leave-to-class="max-h-0 overflow-hidden"
|
|
||||||
>
|
|
||||||
<div v-if="opened" class="flex flex-col gap-1.5 px-3">
|
|
||||||
<SectionFields
|
<SectionFields
|
||||||
:fields="section.fields"
|
:fields="section.fields"
|
||||||
v-model="lead.data"
|
v-model="lead.data"
|
||||||
@update="updateField"
|
@update="updateField"
|
||||||
/>
|
/>
|
||||||
</div>
|
</Section>
|
||||||
</transition>
|
|
||||||
</Toggler>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -197,10 +174,10 @@ import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
|||||||
import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
||||||
import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
||||||
import LayoutHeader from '@/components/LayoutHeader.vue'
|
import LayoutHeader from '@/components/LayoutHeader.vue'
|
||||||
import Toggler from '@/components/Toggler.vue'
|
|
||||||
import Activities from '@/components/Activities.vue'
|
import Activities from '@/components/Activities.vue'
|
||||||
import UserAvatar from '@/components/UserAvatar.vue'
|
import UserAvatar from '@/components/UserAvatar.vue'
|
||||||
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
||||||
|
import Section from '@/components/Section.vue'
|
||||||
import SectionFields from '@/components/SectionFields.vue'
|
import SectionFields from '@/components/SectionFields.vue'
|
||||||
import {
|
import {
|
||||||
leadStatuses,
|
leadStatuses,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user