diff --git a/app/javascript/dashboard/components-next/message/Message.vue b/app/javascript/dashboard/components-next/message/Message.vue index da33139e0..1470fb6a3 100644 --- a/app/javascript/dashboard/components-next/message/Message.vue +++ b/app/javascript/dashboard/components-next/message/Message.vue @@ -13,10 +13,25 @@ import Avatar from 'next/avatar/Avatar.vue'; import TextBubble from './bubbles/Text.vue'; import ActivityBubble from './bubbles/Activity.vue'; +import MediaBubble from './bubbles/Media.vue'; import MessageError from './MessageError.vue'; import MessageMeta from './MessageMeta.vue'; +/** + * @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} Sender * @property {Object} additional_attributes - Additional attributes of the sender @@ -37,18 +52,19 @@ import MessageMeta from './MessageMeta.vue'; /** * @typedef {Object} Props + * @property {('sent'|'delivered'|'read'|'failed')} status - The delivery status of the message + * @property {ContentAttributes} [contentAttributes={}] - Additional attributes of the message content + * @property {Attachment[]} [attachments=[]] - The attachments associated with the message + * @property {Sender|null} [sender=null] - The sender information + * @property {boolean} [private=false] - Whether the message is private + * @property {number|null} [senderId=null] - The ID of the sender + * @property {number} createdAt - Timestamp when the message was created + * @property {number} currentUserId - The ID of the current user * @property {number} id - The unique identifier for the message * @property {number} messageType - The type of message (must be one of MESSAGE_TYPES) - * @property {('sent'|'delivered'|'read'|'failed')} status - The delivery status of the message - * @property {boolean} [private=false] - Whether the message is private - * @property {number} createdAt - Timestamp when the message was created - * @property {Sender|null} [sender=null] - The sender information - * @property {ContentAttributes} [contentAttributes={}] - Additional attributes of the message content - * @property {number|null} [senderId=null] - The ID of the sender - * @property {string|null} [senderType=null] - The type of the sender * @property {string|null} [error=null] - Error message if the message failed to send + * @property {string|null} [senderType=null] - The type of the sender * @property {string} content - The message content - * @property {number} currentUserId - The ID of the current user */ const props = defineProps({ @@ -63,6 +79,10 @@ const props = defineProps({ required: true, validator: value => Object.values(MESSAGE_STATUS).includes(value), }, + attachments: { + type: Array, + default: () => [], + }, private: { type: Boolean, default: false, @@ -188,6 +208,14 @@ const shouldShowAvatar = computed(() => { return true; }); +const componentToRender = computed(() => { + if (props.attachments.length === 1) { + return MediaBubble; + } + + return TextBubble; +}); + provideMessageContext({ variant, orientation, @@ -218,7 +246,11 @@ provideMessageContext({ > - + +import { ref, computed } from 'vue'; +import BaseBubble from './Base.vue'; +import Button from 'next/button/Button.vue'; + +/** + * @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 hasError = ref(false); + + + diff --git a/app/javascript/dashboard/components-next/message/constants.js b/app/javascript/dashboard/components-next/message/constants.js index fa30d79c6..e7d5f0976 100644 --- a/app/javascript/dashboard/components-next/message/constants.js +++ b/app/javascript/dashboard/components-next/message/constants.js @@ -33,3 +33,16 @@ export const MESSAGE_STATUS = { FAILED: 'failed', PROGRESS: 'progress', }; + +export const ATTACHMENT_TYPES = { + IMAGE: 'image', + AUDIO: 'audio', + VIDEO: 'video', + FILE: 'file', + LOCATION: 'location', + FALLBACK: 'fallback', + SHARE: 'share', + STORY_MENTION: 'story_mention', + CONTACT: 'contact', + IG_REEL: 'ig_reel', +}; diff --git a/app/javascript/dashboard/components-next/message/fixtures/textWithMedia.js b/app/javascript/dashboard/components-next/message/fixtures/textWithMedia.js index 18f96b7d8..c622af4cc 100644 --- a/app/javascript/dashboard/components-next/message/fixtures/textWithMedia.js +++ b/app/javascript/dashboard/components-next/message/fixtures/textWithMedia.js @@ -332,9 +332,9 @@ export default camelcaseKeys( account_id: 2, extension: null, data_url: - 'http://localhost:3000/rails/active_storage/blobs/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaUFLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--0f76a0caba1df9a5217630b5ca1fdfb09c9111d3/image.png', + 'https://images.pexels.com/photos/28379994/pexels-photo-28379994/free-photo-of-a-laptop-with-a-yellow-phone-on-top-of-it.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2', thumb_url: - 'http://localhost:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBBaUFLIiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--0f76a0caba1df9a5217630b5ca1fdfb09c9111d3/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RTNKbGMybDZaVjkwYjE5bWFXeHNXd2RwQWZvdyIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--ebe60765d222d11ade39165eae49cc4b2de18d89/image.png', + 'https://images.pexels.com/photos/28379994/pexels-photo-28379994/free-photo-of-a-laptop-with-a-yellow-phone-on-top-of-it.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2', file_size: 983912, width: null, height: null,