feat: added whatsapp messages on lead/deal page in whatsapp tab
This commit is contained in:
parent
e04a4c6b4c
commit
61c8b16ff1
@ -336,3 +336,12 @@ def get_linked_tasks(name):
|
||||
],
|
||||
)
|
||||
return tasks or []
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_whatsapp_messages(name):
|
||||
whatsapp_messages = frappe.db.get_all(
|
||||
"WhatsApp Message",
|
||||
filters={"reference_doctype": "CRM Lead", "reference_name": name, "status": ("not in", ["failed", "Success"])},
|
||||
fields=["name", "type", "to", "from", "content_type", "creation", "message", "status"],
|
||||
)
|
||||
return whatsapp_messages or []
|
||||
@ -35,6 +35,16 @@
|
||||
</template>
|
||||
<span>{{ __('New Task') }}</span>
|
||||
</Button>
|
||||
<Button
|
||||
v-else-if="title == 'WhatsApp'"
|
||||
variant="solid"
|
||||
@click="$refs.whatsappBox.show = true"
|
||||
>
|
||||
<template #prefix>
|
||||
<FeatherIcon name="plus" class="h-4 w-4" />
|
||||
</template>
|
||||
<span>{{ __('New WhatsApp Message') }}</span>
|
||||
</Button>
|
||||
<Dropdown
|
||||
v-else
|
||||
:options="[
|
||||
@ -58,6 +68,11 @@
|
||||
label: __('New Task'),
|
||||
onClick: () => showTask(),
|
||||
},
|
||||
{
|
||||
icon: h(WhatsAppIcon, { class: 'h-4 w-4' }),
|
||||
label: __('New WhatsApp Message'),
|
||||
onClick: () => ($refs.emailBox.show = true),
|
||||
},
|
||||
]"
|
||||
@click.stop
|
||||
>
|
||||
@ -338,6 +353,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<WhatsAppArea
|
||||
v-else-if="title == 'WhatsApp'"
|
||||
class="px-10"
|
||||
:messages="activities"
|
||||
/>
|
||||
<div v-else v-for="(activity, i) in activities" class="activity">
|
||||
<div class="grid grid-cols-[30px_minmax(auto,_1fr)] gap-4 px-10">
|
||||
<div
|
||||
@ -768,6 +788,8 @@ import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
||||
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
||||
import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue'
|
||||
import WhatsAppArea from '@/components/WhatsAppArea.vue'
|
||||
import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
|
||||
import DurationIcon from '@/components/Icons/DurationIcon.vue'
|
||||
import CalendarIcon from '@/components/Icons/CalendarIcon.vue'
|
||||
@ -875,6 +897,13 @@ const all_activities = createResource({
|
||||
},
|
||||
})
|
||||
|
||||
const whatsappMessages = createResource({
|
||||
url: 'crm.api.activities.get_whatsapp_messages',
|
||||
params: { name: doc.value.data.name },
|
||||
cache: ['whatsapp', doc.value.data.name],
|
||||
auto: true,
|
||||
})
|
||||
|
||||
function get_activities() {
|
||||
if (!all_activities.data?.versions) return []
|
||||
if (!all_activities.data?.calls.length)
|
||||
@ -900,6 +929,9 @@ const activities = computed(() => {
|
||||
} else if (props.title == 'Notes') {
|
||||
if (!all_activities.data?.notes) return []
|
||||
return sortByCreation(all_activities.data.notes)
|
||||
} else if (props.title == 'WhatsApp') {
|
||||
if (!whatsappMessages.data) return []
|
||||
return sortByCreation(whatsappMessages.data)
|
||||
}
|
||||
activities.forEach((activity) => {
|
||||
activity.icon = timelineIcon(activity.activity_type, activity.is_lead)
|
||||
@ -958,6 +990,8 @@ const emptyText = computed(() => {
|
||||
text = 'No Notes'
|
||||
} else if (props.title == 'Tasks') {
|
||||
text = 'No Tasks'
|
||||
} else if (props.title == 'WhatsApp') {
|
||||
text = 'No WhatsApp Messages'
|
||||
}
|
||||
return text
|
||||
})
|
||||
@ -972,6 +1006,8 @@ const emptyTextIcon = computed(() => {
|
||||
icon = NoteIcon
|
||||
} else if (props.title == 'Tasks') {
|
||||
icon = TaskIcon
|
||||
} else if (props.title == 'WhatsApp') {
|
||||
icon = WhatsAppIcon
|
||||
}
|
||||
return h(icon, { class: 'text-gray-500' })
|
||||
})
|
||||
|
||||
16
frontend/src/components/Icons/CheckIcon.vue
Normal file
16
frontend/src/components/Icons/CheckIcon.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-check"
|
||||
>
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
</template>
|
||||
17
frontend/src/components/Icons/DoubleCheckIcon.vue
Normal file
17
frontend/src/components/Icons/DoubleCheckIcon.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-check-check"
|
||||
>
|
||||
<path d="M18 6 7 17l-5-5" />
|
||||
<path d="m22 10-7.5 7.5L13 16" />
|
||||
</svg>
|
||||
</template>
|
||||
28
frontend/src/components/Icons/WhatsAppIcon.vue
Normal file
28
frontend/src/components/Icons/WhatsAppIcon.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6 15.5C7.5 16.5 10.3367 17.2101 12.0757 16.7964C13.8147 16.3826 15.3488 15.3614 16.4015 13.9167C17.4541 12.472 17.9562 10.6988 17.8172 8.91668C17.6781 7.13456 16.9072 5.46069 15.6432 4.19671C14.3792 2.93273 12.7053 2.16176 10.9232 2.02273C9.14108 1.8837 7.36789 2.38575 5.92318 3.43842C4.47847 4.49109 3.45724 6.02514 3.04352 7.76414C2.62979 9.50314 3 12 4 13.5L2.5 17L6 15.5Z"
|
||||
stroke="currentColor"
|
||||
stroke-width="1"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M11.3355 12.3844L12 11.5C12.4877 11.0123 12.775 11.209 13.4481 11.4793C13.4824 11.4931 13.515 11.5112 13.5445 11.5333L13.8563 11.7664C14.0434 11.8987 14.0487 12.1733 13.8668 12.3126L13.2106 12.8153C12.9462 13.0178 12.5923 13.0604 12.2947 12.91C11.5548 12.536 10.1264 11.74 9.11332 10.7151C8.13237 9.72267 7.42487 8.40546 7.07965 7.68204C6.92664 7.3614 7.0003 6.98556 7.24735 6.72951L7.85039 6.10451C8.00431 5.94497 8.26796 5.97191 8.38609 6.15923L8.79347 6.72951C9.11332 7.24052 8.65816 7.67639 8.38609 7.85843L7.5 8.49417"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M11.3355 12.3844L12 11.5C12.4877 11.0123 12.775 11.209 13.4481 11.4793C13.4824 11.4931 13.515 11.5112 13.5445 11.5333L13.8563 11.7664C14.0434 11.8987 14.0487 12.1733 13.8668 12.3126L13.2106 12.8153C12.9462 13.0178 12.5923 13.0604 12.2947 12.91C11.5548 12.536 10.1264 11.74 9.11332 10.7151C8.13237 9.72267 7.42487 8.40546 7.07965 7.68204C6.92664 7.3614 7.0003 6.98556 7.24735 6.72951L7.85039 6.10451C8.00431 5.94497 8.26796 5.97191 8.38609 6.15923L8.79347 6.72951C9.11332 7.24052 8.65816 7.67639 8.38609 7.85843L7.5 8.49417"
|
||||
stroke="currentColor"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
40
frontend/src/components/WhatsAppArea.vue
Normal file
40
frontend/src/components/WhatsAppArea.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-for="whatsapp in messages"
|
||||
:key="whatsapp.name"
|
||||
class="flex"
|
||||
:class="{ 'justify-end': whatsapp.type == 'Outgoing' }"
|
||||
>
|
||||
<div
|
||||
class="mb-3 inline-flex max-w-[90%] gap-2 rounded-md bg-gray-50 p-2 text-base shadow-sm"
|
||||
>
|
||||
<div>{{ whatsapp.message }}</div>
|
||||
<div class="-mb-1 flex items-end gap-1 text-gray-600 shrink-0">
|
||||
<Tooltip :text="dateFormat(whatsapp.creation, 'ddd, MMM D, YYYY')">
|
||||
<div class="text-2xs">{{ dateFormat(whatsapp.creation, 'hh:mm a') }}</div>
|
||||
</Tooltip>
|
||||
<div v-if="whatsapp.type == 'Outgoing'">
|
||||
<CheckIcon v-if="whatsapp.status == 'sent'" class="size-4" />
|
||||
<DoubleCheckIcon
|
||||
v-else-if="['read', 'delivered'].includes(whatsapp.status)"
|
||||
class="size-4"
|
||||
:class="{ 'text-blue-500': whatsapp.status == 'read' }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import CheckIcon from '@/components/Icons/CheckIcon.vue'
|
||||
import DoubleCheckIcon from '@/components/Icons/DoubleCheckIcon.vue'
|
||||
import { Tooltip } from 'frappe-ui'
|
||||
import { dateFormat } from '@/utils'
|
||||
|
||||
const props = defineProps({
|
||||
messages: Array,
|
||||
})
|
||||
</script>
|
||||
@ -293,6 +293,7 @@ import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
||||
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
||||
import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue'
|
||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||
import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
||||
import ArrowUpRightIcon from '@/components/Icons/ArrowUpRightIcon.vue'
|
||||
@ -459,6 +460,11 @@ const tabs = [
|
||||
label: __('Notes'),
|
||||
icon: NoteIcon,
|
||||
},
|
||||
{
|
||||
name: 'WhatsApp',
|
||||
label: __('WhatsApp'),
|
||||
icon: WhatsAppIcon,
|
||||
},
|
||||
]
|
||||
|
||||
const detailSections = computed(() => {
|
||||
|
||||
@ -260,6 +260,7 @@ import EmailIcon from '@/components/Icons/EmailIcon.vue'
|
||||
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
|
||||
import TaskIcon from '@/components/Icons/TaskIcon.vue'
|
||||
import NoteIcon from '@/components/Icons/NoteIcon.vue'
|
||||
import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue'
|
||||
import IndicatorIcon from '@/components/Icons/IndicatorIcon.vue'
|
||||
import CameraIcon from '@/components/Icons/CameraIcon.vue'
|
||||
import LinkIcon from '@/components/Icons/LinkIcon.vue'
|
||||
@ -423,6 +424,11 @@ const tabs = [
|
||||
label: __('Notes'),
|
||||
icon: NoteIcon,
|
||||
},
|
||||
{
|
||||
name: 'WhatsApp',
|
||||
label: __('WhatsApp'),
|
||||
icon: WhatsAppIcon,
|
||||
},
|
||||
]
|
||||
|
||||
function validateFile(file) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user