fix: created SLA Section component & added in lead/deal page
This commit is contained in:
parent
86984abd2b
commit
bf996a3cbd
114
frontend/src/components/SLASection.vue
Normal file
114
frontend/src/components/SLASection.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-1.5 border-b px-6 py-3">
|
||||
<div
|
||||
v-for="s in slaSection"
|
||||
:key="s.label"
|
||||
class="flex items-center gap-2 text-base leading-5"
|
||||
>
|
||||
<div class="w-[106px] text-sm text-gray-600">{{ s.label }}</div>
|
||||
<div class="grid min-h-[28px] items-center">
|
||||
<Tooltip
|
||||
v-if="s.tooltipText"
|
||||
:text="s.tooltipText"
|
||||
class="ml-2 cursor-pointer"
|
||||
>
|
||||
<Badge
|
||||
v-if="s.type == 'Badge'"
|
||||
class="-ml-1"
|
||||
:label="s.value"
|
||||
variant="subtle"
|
||||
:theme="s.color"
|
||||
/>
|
||||
<div v-else>{{ s.value }}</div>
|
||||
</Tooltip>
|
||||
<Dropdown
|
||||
class="form-control"
|
||||
v-if="s.type == 'Select'"
|
||||
:options="s.options"
|
||||
>
|
||||
<template #default="{ open }">
|
||||
<Button :label="s.value">
|
||||
<template #suffix>
|
||||
<FeatherIcon
|
||||
:name="open ? 'chevron-up' : 'chevron-down'"
|
||||
class="h-4"
|
||||
/>
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Dropdown, Badge, Tooltip, FeatherIcon } from 'frappe-ui'
|
||||
import { timeAgo, dateFormat, formatTime, dateTooltipFormat } from '@/utils'
|
||||
import { statusesStore } from '@/stores/statuses'
|
||||
import { computed, defineModel } from 'vue'
|
||||
|
||||
const data = defineModel()
|
||||
const emit = defineEmits(['updateField'])
|
||||
|
||||
const { communicationStatuses } = statusesStore()
|
||||
|
||||
let slaSection = computed(() => {
|
||||
let sections = []
|
||||
if (data.value.first_response_time) {
|
||||
sections.push({
|
||||
label: 'Fulfilled In',
|
||||
type: 'Duration',
|
||||
value: formatTime(data.value.first_response_time),
|
||||
tooltipText: dateFormat(data.value.first_responded_on, dateTooltipFormat),
|
||||
})
|
||||
}
|
||||
|
||||
let status = data.value.sla_status
|
||||
let tooltipText = status
|
||||
let color =
|
||||
data.value.sla_status == 'Failed'
|
||||
? 'red'
|
||||
: data.value.sla_status == 'Fulfilled'
|
||||
? 'green'
|
||||
: 'orange'
|
||||
|
||||
if (status == 'First Response Due') {
|
||||
status = timeAgo(data.value.response_by)
|
||||
tooltipText = dateFormat(data.value.response_by, dateTooltipFormat)
|
||||
if (new Date(data.value.response_by) < new Date()) {
|
||||
color = 'red'
|
||||
}
|
||||
}
|
||||
|
||||
sections.push(
|
||||
...[
|
||||
{
|
||||
label: 'SLA',
|
||||
type: 'Badge',
|
||||
value: status,
|
||||
tooltipText: tooltipText,
|
||||
color: color,
|
||||
},
|
||||
{
|
||||
label: 'Status',
|
||||
value: data.value.communication_status,
|
||||
type: 'Select',
|
||||
options: communicationStatuses.data?.map((status) => ({
|
||||
label: status.name,
|
||||
value: status.name,
|
||||
onClick: () =>
|
||||
emit('updateField', 'communication_status', status.name),
|
||||
})),
|
||||
},
|
||||
]
|
||||
)
|
||||
return sections
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
:deep(.form-control button) {
|
||||
border-color: transparent;
|
||||
background: white;
|
||||
}
|
||||
</style>
|
||||
@ -99,72 +99,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="deal.data.sla_status" class="flex flex-col gap-2 border-b p-5">
|
||||
<div
|
||||
v-if="deal.data.sla_status == 'First Response Due'"
|
||||
class="flex items-center gap-4 text-base leading-5"
|
||||
>
|
||||
<div class="w-[106px] text-gray-600">Response By</div>
|
||||
<Tooltip
|
||||
:text="dateFormat(deal.data.response_by, 'ddd, MMM D, YYYY h:mm A')"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
{{ timeAgo(deal.data.response_by) }}
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
v-if="deal.data.sla_status == 'Fulfilled'"
|
||||
class="flex items-center gap-4 text-base leading-5"
|
||||
>
|
||||
<div class="w-[106px] text-gray-600">Fulfilled In</div>
|
||||
<Tooltip
|
||||
:text="
|
||||
dateFormat(
|
||||
deal.data.first_responded_on,
|
||||
'ddd, MMM D, YYYY h:mm A'
|
||||
)
|
||||
"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
{{ formatTime(deal.data.first_response_time) }}
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
deal.data.sla_status == 'Failed' && deal.data.first_responded_on
|
||||
"
|
||||
class="flex items-center gap-4 text-base leading-5"
|
||||
>
|
||||
<div class="w-[106px] text-gray-600">Fulfilled In</div>
|
||||
<Tooltip
|
||||
:text="
|
||||
dateFormat(
|
||||
deal.data.first_responded_on,
|
||||
'ddd, MMM D, YYYY h:mm A'
|
||||
)
|
||||
"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
{{ formatTime(deal.data.first_response_time) }}
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="flex items-center gap-4 text-base leading-5">
|
||||
<div class="w-[106px] text-gray-600">Status</div>
|
||||
<div class="">
|
||||
<Badge
|
||||
:label="deal.data.sla_status"
|
||||
variant="outline"
|
||||
:theme="
|
||||
deal.data.sla_status === 'Failed'
|
||||
? 'red'
|
||||
: deal.data.sla_status === 'Fulfilled'
|
||||
? 'green'
|
||||
: 'gray'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SLASection
|
||||
v-if="deal.data.sla_status"
|
||||
v-model="deal.data"
|
||||
@updateField="updateField"
|
||||
/>
|
||||
<div class="flex flex-1 flex-col justify-between overflow-hidden">
|
||||
<div class="flex flex-col overflow-y-auto">
|
||||
<div
|
||||
@ -346,13 +285,8 @@ import ContactModal from '@/components/Modals/ContactModal.vue'
|
||||
import Link from '@/components/Controls/Link.vue'
|
||||
import Section from '@/components/Section.vue'
|
||||
import SectionFields from '@/components/SectionFields.vue'
|
||||
import {
|
||||
openWebsite,
|
||||
createToast,
|
||||
dateFormat,
|
||||
timeAgo,
|
||||
formatTime,
|
||||
} from '@/utils'
|
||||
import SLASection from '@/components/SLASection.vue'
|
||||
import { openWebsite, createToast } from '@/utils'
|
||||
import { usersStore } from '@/stores/users'
|
||||
import { contactsStore } from '@/stores/contacts'
|
||||
import { organizationsStore } from '@/stores/organizations'
|
||||
|
||||
@ -139,19 +139,11 @@
|
||||
</div>
|
||||
</template>
|
||||
</FileUploader>
|
||||
<div v-if="lead.data.sla_status" class="flex flex-col gap-2 border-b p-5">
|
||||
<div
|
||||
v-for="s in slaSection"
|
||||
:key="s.label"
|
||||
class="flex items-center gap-4 text-base leading-5"
|
||||
>
|
||||
<div class="w-[106px] text-gray-600">{{ s.label }}</div>
|
||||
<Tooltip :text="s.tooltipText" class="cursor-pointer">
|
||||
<div v-if="!s.isBadge">{{ s.value }}</div>
|
||||
<Badge v-else :label="s.value" variant="subtle" :theme="s.color" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<SLASection
|
||||
v-if="lead.data.sla_status"
|
||||
v-model="lead.data"
|
||||
@updateField="updateField"
|
||||
/>
|
||||
<div class="flex flex-1 flex-col justify-between overflow-hidden">
|
||||
<div class="flex flex-col overflow-y-auto">
|
||||
<div
|
||||
@ -199,15 +191,9 @@ import UserAvatar from '@/components/UserAvatar.vue'
|
||||
import OrganizationModal from '@/components/Modals/OrganizationModal.vue'
|
||||
import Section from '@/components/Section.vue'
|
||||
import SectionFields from '@/components/SectionFields.vue'
|
||||
import SLASection from '@/components/SLASection.vue'
|
||||
import Link from '@/components/Controls/Link.vue'
|
||||
import {
|
||||
openWebsite,
|
||||
createToast,
|
||||
dateFormat,
|
||||
timeAgo,
|
||||
formatTime,
|
||||
dateTooltipFormat,
|
||||
} from '@/utils'
|
||||
import { openWebsite, createToast } from '@/utils'
|
||||
import { usersStore } from '@/stores/users'
|
||||
import { contactsStore } from '@/stores/contacts'
|
||||
import { organizationsStore } from '@/stores/organizations'
|
||||
@ -222,7 +208,6 @@ import {
|
||||
Avatar,
|
||||
Tabs,
|
||||
Breadcrumbs,
|
||||
Badge,
|
||||
call,
|
||||
} from 'frappe-ui'
|
||||
import { ref, computed } from 'vue'
|
||||
@ -380,41 +365,4 @@ function updateField(name, value, callback) {
|
||||
callback?.()
|
||||
})
|
||||
}
|
||||
|
||||
let slaSection = computed(() => {
|
||||
let sections = []
|
||||
if (lead.data.first_response_time) {
|
||||
sections.push({
|
||||
label: 'Fulfilled In',
|
||||
value: formatTime(lead.data.first_response_time),
|
||||
tooltipText: dateFormat(lead.data.first_responded_on, dateTooltipFormat),
|
||||
})
|
||||
}
|
||||
|
||||
let status = lead.data.sla_status
|
||||
let tooltipText = status
|
||||
let color =
|
||||
lead.data.sla_status == 'Failed'
|
||||
? 'red'
|
||||
: lead.data.sla_status == 'Fulfilled'
|
||||
? 'green'
|
||||
: 'orange'
|
||||
|
||||
if (status == 'First Response Due') {
|
||||
status = timeAgo(lead.data.response_by)
|
||||
tooltipText = dateFormat(lead.data.response_by, dateTooltipFormat)
|
||||
if (new Date(lead.data.response_by) < new Date()) {
|
||||
color = 'red'
|
||||
}
|
||||
}
|
||||
|
||||
sections.push({
|
||||
label: 'Status',
|
||||
isBadge: true,
|
||||
value: status,
|
||||
tooltipText: tooltipText,
|
||||
color: color,
|
||||
})
|
||||
return sections
|
||||
})
|
||||
</script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user