feat: add attachment only component

This commit is contained in:
Shivam Mishra
2024-11-28 18:27:55 +05:30
parent 44b4c7ce14
commit b304e86f4f
4 changed files with 197 additions and 15 deletions
@@ -17,6 +17,7 @@ import ActivityBubble from './bubbles/Activity.vue';
import ImageBubble from './bubbles/Image.vue';
import FileBubble from './bubbles/File.vue';
import AudioBubble from './bubbles/Audio.vue';
import AttachmentsBubble from './bubbles/Attachments.vue';
import MessageError from './MessageError.vue';
import MessageMeta from './MessageMeta.vue';
@@ -219,6 +220,10 @@ const componentToRender = computed(() => {
if (fileType === ATTACHMENT_TYPES.AUDIO) return AudioBubble;
}
if (props.attachments.length > 1 && !props.content) {
return AttachmentsBubble;
}
return TextBubble;
});
@@ -0,0 +1,86 @@
<script setup>
import { computed } from 'vue';
import BaseBubble from 'next/message/bubbles/Base.vue';
import ImageChip from 'next/message/chips/Image.vue';
import VideoChip from 'next/message/chips/Video.vue';
import AudioChip from 'next/message/chips/Audio.vue';
import FileChip from 'next/message/chips/File.vue';
import { ATTACHMENT_TYPES } from '../constants';
/**
* @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
*/
const props = defineProps({
attachments: {
type: Array,
default: () => [],
},
});
const mediaAttachments = computed(() => {
const allowedTypes = [ATTACHMENT_TYPES.IMAGE, ATTACHMENT_TYPES.VIDEO];
const mediaTypes = props.attachments.filter(attachment =>
allowedTypes.includes(attachment.fileType)
);
return mediaTypes.sort(
(a, b) =>
allowedTypes.indexOf(a.fileType) - allowedTypes.indexOf(b.fileType)
);
});
const recordings = computed(() => {
return props.attachments.filter(
attachment => attachment.fileType === ATTACHMENT_TYPES.AUDIO
);
});
const files = computed(() => {
return props.attachments.filter(
attachment => attachment.fileType === ATTACHMENT_TYPES.FILE
);
});
</script>
<template>
<BaseBubble class="grid gap-2 bg-transparent">
<div v-if="mediaAttachments.length" class="flex gap-1">
<template v-for="attachment in mediaAttachments" :key="attachment.id">
<ImageChip
v-if="attachment.fileType === ATTACHMENT_TYPES.IMAGE"
:attachment="attachment"
/>
<VideoChip
v-else-if="attachment.fileType === ATTACHMENT_TYPES.VIDEO"
:attachment="attachment"
/>
</template>
</div>
<div v-if="recordings.length" class="flex flex-wrap gap-1">
<AudioChip
v-for="attachment in recordings"
:key="attachment.id"
class="bg-n-alpha-3 dark:bg-n-alpha-2 text-n-slate-12"
:attachment="attachment"
/>
</div>
<div v-if="files.length" class="flex flex-wrap gap-1">
<FileChip
v-for="attachment in files"
:key="attachment.id"
:attachment="attachment"
/>
</div>
</BaseBubble>
</template>
@@ -70,9 +70,9 @@ const files = computed(() => {
</script>
<template>
<BaseBubble class="p-3 space-y-[10px]">
<BaseBubble class="p-3 grid gap-3">
<span v-if="content" v-html="formattedContent" />
<div v-if="mediaAttachments.length" class="flex gap-[10px]">
<div v-if="mediaAttachments.length" class="flex gap-2">
<template v-for="attachment in mediaAttachments" :key="attachment.id">
<ImageChip
v-if="attachment.fileType === ATTACHMENT_TYPES.IMAGE"
@@ -84,7 +84,7 @@ const files = computed(() => {
/>
</template>
</div>
<div v-if="recordings.length" class="flex flex-wrap gap-[10px]">
<div v-if="recordings.length" class="flex flex-wrap gap-2">
<AudioChip
v-for="attachment in recordings"
:key="attachment.id"
@@ -92,7 +92,7 @@ const files = computed(() => {
:attachment="attachment"
/>
</div>
<div v-if="files.length" class="flex flex-wrap gap-[10px]">
<div v-if="files.length" class="flex flex-wrap gap-2">
<FileChip
v-for="attachment in files"
:key="attachment.id"
@@ -1212,27 +1212,31 @@ export default camelcaseKeys(
},
{
id: 5323,
content: null,
content: 'These are all the files you requested',
inbox_id: 486,
echo_id: '9f7432284767',
conversation_id: 1016,
message_type: 1,
message_type: 0,
content_type: 'text',
status: 'sent',
content_attributes: {},
created_at: 1732795624,
private: false,
source_id: null,
sender_type: 'Contact',
sender_id: 599,
sender: {
id: 1,
name: 'John',
available_name: 'John',
avatar_url:
'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaDBLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--4e625d80e7ef2dc41354392bc214832fbe640840/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RTNKbGMybDZaVjkwYjE5bWFXeHNXd2RwQWZvdyIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--ebe60765d222d11ade39165eae49cc4b2de18d89/picologo.png',
type: 'user',
availability_status: 'offline',
thumbnail:
'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaDBLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--4e625d80e7ef2dc41354392bc214832fbe640840/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RTNKbGMybDZaVjkwYjE5bWFXeHNXd2RwQWZvdyIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--ebe60765d222d11ade39165eae49cc4b2de18d89/picologo.png',
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: [
{
@@ -1263,6 +1267,93 @@ export default camelcaseKeys(
width: null,
height: null,
},
{
id: 28,
message_id: 5323,
file_type: 'file',
account_id: 2,
extension: null,
data_url:
'http://localhost:3000/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXdLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aa5f4c3a2a034b6e68800d4787d369254ab1eb4/multi.zip',
thumb_url:
'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXdLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aa5f4c3a2a034b6e68800d4787d369254ab1eb4/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBPZ2h3Ym1jNkUzSmxjMmw2WlY5MGIxOW1hV3hzV3dkcEFmb3ciLCJleHAiOm51bGwsInB1ciI6InZhcmlhdGlvbiJ9fQ==--328463286cffa0d7d9a36a3a30bfa1daed3a5ee6/multi.webp',
file_size: 58696,
width: null,
height: null,
},
],
},
{
id: 5323,
content: null,
inbox_id: 486,
echo_id: '9f7432284767',
conversation_id: 1016,
message_type: 0,
content_type: 'text',
status: 'sent',
content_attributes: {},
created_at: 1732795624,
private: false,
source_id: null,
sender_type: 'Contact',
sender_id: 599,
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: 27,
message_id: 5323,
file_type: 'image',
account_id: 2,
extension: null,
data_url:
'http://localhost:3000/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXNLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--08dfc1dcfd6733fe82ad318036e8f5926f2d7634/scrubbing.webp',
thumb_url:
'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXNLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--08dfc1dcfd6733fe82ad318036e8f5926f2d7634/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBPZ2h3Ym1jNkUzSmxjMmw2WlY5MGIxOW1hV3hzV3dkcEFmb3ciLCJleHAiOm51bGwsInB1ciI6InZhcmlhdGlvbiJ9fQ==--328463286cffa0d7d9a36a3a30bfa1daed3a5ee6/scrubbing.webp',
file_size: 26126,
width: null,
height: null,
},
{
id: 28,
message_id: 5323,
file_type: 'image',
account_id: 2,
extension: null,
data_url:
'http://localhost:3000/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXdLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aa5f4c3a2a034b6e68800d4787d369254ab1eb4/multi.webp',
thumb_url:
'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXdLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aa5f4c3a2a034b6e68800d4787d369254ab1eb4/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBPZ2h3Ym1jNkUzSmxjMmw2WlY5MGIxOW1hV3hzV3dkcEFmb3ciLCJleHAiOm51bGwsInB1ciI6InZhcmlhdGlvbiJ9fQ==--328463286cffa0d7d9a36a3a30bfa1daed3a5ee6/multi.webp',
file_size: 58696,
width: null,
height: null,
},
{
id: 28,
message_id: 5323,
file_type: 'file',
account_id: 2,
extension: null,
data_url:
'http://localhost:3000/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXdLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aa5f4c3a2a034b6e68800d4787d369254ab1eb4/list-with-all-data.csv',
thumb_url:
'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaXdLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--3aa5f4c3a2a034b6e68800d4787d369254ab1eb4/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBPZ2h3Ym1jNkUzSmxjMmw2WlY5MGIxOW1hV3hzV3dkcEFmb3ciLCJleHAiOm51bGwsInB1ciI6InZhcmlhdGlvbiJ9fQ==--328463286cffa0d7d9a36a3a30bfa1daed3a5ee6/multi.webp',
file_size: 58696,
width: null,
height: null,
},
],
},
],