feat: add location bubble
This commit is contained in:
@@ -21,6 +21,7 @@ import VideoBubble from './bubbles/Video.vue';
|
||||
import InstagramStoryBubble from './bubbles/InstagramStory.vue';
|
||||
import AttachmentsBubble from './bubbles/Attachments.vue';
|
||||
import EmailBubble from './bubbles/Email/Index.vue';
|
||||
import LocationBubble from './bubbles/Location.vue';
|
||||
|
||||
import MessageError from './MessageError.vue';
|
||||
import MessageMeta from './MessageMeta.vue';
|
||||
@@ -250,6 +251,7 @@ const componentToRender = computed(() => {
|
||||
if (fileType === ATTACHMENT_TYPES.AUDIO) return AudioBubble;
|
||||
if (fileType === ATTACHMENT_TYPES.VIDEO) return VideoBubble;
|
||||
if (fileType === ATTACHMENT_TYPES.IG_REEL) return VideoBubble;
|
||||
if (fileType === ATTACHMENT_TYPES.LOCATION) return LocationBubble;
|
||||
}
|
||||
|
||||
if (props.attachments.length > 1 && !props.content) {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, nextTick } from 'vue';
|
||||
import BaseBubble from './Base.vue';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
import maplibregl from 'maplibre-gl';
|
||||
|
||||
/**
|
||||
* @typedef {Object} Attachment
|
||||
* @property {number} id - Unique identifier for the attachment
|
||||
* @property {number} messageId - ID of the associated message
|
||||
* @property {'image'|'audio'|'video'|'file'|'location'|'fallback'|'share'|'story_mention'|'contact'|'ig_reel'} fileType - Type of the attachment (file or image)
|
||||
* @property {number} accountId - ID of the associated account
|
||||
* @property {string|null} extension - File extension
|
||||
* @property {string} dataUrl - URL to access the full attachment data
|
||||
* @property {string} thumbUrl - URL to access the thumbnail version
|
||||
* @property {number} fileSize - Size of the file in bytes
|
||||
* @property {number|null} width - Width of the image if applicable
|
||||
* @property {number|null} height - Height of the image if applicable
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Props
|
||||
* @property {Attachment[]} [attachments=[]] - The attachments associated with the message
|
||||
*/
|
||||
|
||||
const props = defineProps({
|
||||
attachments: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const attachment = computed(() => {
|
||||
return props.attachments[0];
|
||||
});
|
||||
|
||||
const lat = computed(() => {
|
||||
return attachment.value.coordinatesLat;
|
||||
});
|
||||
const long = computed(() => {
|
||||
return attachment.value.coordinatesLong;
|
||||
});
|
||||
|
||||
const title = computed(() => {
|
||||
return attachment.value.fallbackTitle;
|
||||
});
|
||||
|
||||
const mapUrl = computed(
|
||||
() => `https://maps.google.com/?q=${lat.value},${long.value}`
|
||||
);
|
||||
|
||||
const setupMap = async () => {
|
||||
await nextTick();
|
||||
const map = new maplibregl.Map({
|
||||
style: 'https://tiles.openfreemap.org/styles/liberty',
|
||||
center: [long.value, lat.value],
|
||||
zoom: 9.5,
|
||||
container: 'map',
|
||||
attributionControl: false,
|
||||
dragPan: false,
|
||||
dragRotate: false,
|
||||
scrollZoom: false,
|
||||
touchZoom: false,
|
||||
touchRotate: false,
|
||||
keyboard: false,
|
||||
doubleClickZoom: false,
|
||||
});
|
||||
|
||||
return map;
|
||||
};
|
||||
|
||||
onMounted(setupMap);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseBubble
|
||||
class="overflow-hidden relative group outline outline-1 outline-n-weak"
|
||||
>
|
||||
<div id="map" class="max-w-md min-w-64 w-full h-36" />
|
||||
<div
|
||||
class="flex gap-2 p-2 items-center text-xs justify-between bg-n-alpha-3"
|
||||
>
|
||||
<div class="flex gap-1 items-center truncate">
|
||||
<Icon icon="i-lucide-map-pin" class="text-n-slate-10 flex-shrink-0" />
|
||||
{{ title }}
|
||||
</div>
|
||||
<a
|
||||
:href="mapUrl"
|
||||
target="blank"
|
||||
class="text-n-slate-12 flex-shrink-0 text-xs"
|
||||
>
|
||||
{{ $t('COMPONENTS.LOCATION_BUBBLE.SEE_ON_MAP') }}
|
||||
</a>
|
||||
</div>
|
||||
</BaseBubble>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@import 'maplibre-gl/dist/maplibre-gl.css';
|
||||
</style>
|
||||
@@ -30,6 +30,49 @@ export default camelcaseKeys(
|
||||
type: 'contact',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 5296,
|
||||
content: '',
|
||||
inbox_id: 486,
|
||||
conversation_id: 1016,
|
||||
message_type: 0,
|
||||
content_type: 'text',
|
||||
status: 'sent',
|
||||
content_attributes: {
|
||||
in_reply_to: null,
|
||||
},
|
||||
created_at: 1732710571,
|
||||
private: false,
|
||||
source_id: null,
|
||||
sender: {
|
||||
additional_attributes: {
|
||||
created_at_ip: '::1',
|
||||
},
|
||||
custom_attributes: {},
|
||||
email: 'anthony@example.com',
|
||||
id: 599,
|
||||
identifier: null,
|
||||
name: 'anthony',
|
||||
phone_number: null,
|
||||
thumbnail: '',
|
||||
type: 'contact',
|
||||
},
|
||||
attachments: [
|
||||
{
|
||||
id: 378,
|
||||
message_id: 5314,
|
||||
file_type: 'location',
|
||||
account_id: 2,
|
||||
coordinates_lat: 37.7937545,
|
||||
coordinates_long: -122.3997472,
|
||||
fallback_title: 'Chatwoot Inc',
|
||||
extension: null,
|
||||
file_size: 287949,
|
||||
width: null,
|
||||
height: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 5297,
|
||||
content: 'Give the team a way to reach you.',
|
||||
|
||||
Reference in New Issue
Block a user