mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 03:57:52 +00:00
fix: Update Instagram story rendering (#8240)
This commit is contained in:
@@ -22,18 +22,7 @@
|
||||
:bcc="emailHeadAttributes.bcc"
|
||||
:is-incoming="isIncoming"
|
||||
/>
|
||||
<blockquote v-if="storyReply" class="story-reply-quote">
|
||||
<span>{{ $t('CONVERSATION.REPLIED_TO_STORY') }}</span>
|
||||
<bubble-image
|
||||
v-if="!hasImgStoryError && storyUrl"
|
||||
:url="storyUrl"
|
||||
@error="onStoryLoadError"
|
||||
/>
|
||||
<bubble-video
|
||||
v-else-if="hasImgStoryError && storyUrl"
|
||||
:url="storyUrl"
|
||||
/>
|
||||
</blockquote>
|
||||
<instagram-story-reply v-if="storyUrl" :story-url="storyUrl" />
|
||||
<bubble-reply-to
|
||||
v-if="inReplyToMessageId && inboxSupportsReplyTo"
|
||||
:message="inReplyTo"
|
||||
@@ -59,10 +48,15 @@
|
||||
</span>
|
||||
<div v-if="!isPending && hasAttachments">
|
||||
<div v-for="attachment in attachments" :key="attachment.id">
|
||||
<instagram-story
|
||||
v-if="isAnInstagramStory"
|
||||
:story-url="attachment.data_url"
|
||||
@error="onMediaLoadError"
|
||||
/>
|
||||
<bubble-image-audio-video
|
||||
v-if="isAttachmentImageVideoAudio(attachment.file_type)"
|
||||
v-else-if="isAttachmentImageVideoAudio(attachment.file_type)"
|
||||
:attachment="attachment"
|
||||
@error="onImageLoadError"
|
||||
@error="onMediaLoadError"
|
||||
/>
|
||||
<bubble-location
|
||||
v-else-if="attachment.file_type === 'location'"
|
||||
@@ -75,9 +69,6 @@
|
||||
:name="data.content"
|
||||
:phone-number="attachment.fallback_title"
|
||||
/>
|
||||
<instagram-image-error-placeholder
|
||||
v-else-if="hasImageError && hasInstagramStory"
|
||||
/>
|
||||
<bubble-file v-else :url="attachment.data_url" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -89,7 +80,6 @@
|
||||
:story-id="`${storyId}`"
|
||||
:is-a-tweet="isATweet"
|
||||
:is-a-whatsapp-channel="isAWhatsAppChannel"
|
||||
:has-instagram-story="hasInstagramStory"
|
||||
:is-email="isEmailContentType"
|
||||
:is-private="data.private"
|
||||
:message-type="data.message_type"
|
||||
@@ -138,19 +128,18 @@
|
||||
<script>
|
||||
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
|
||||
import BubbleActions from './bubble/Actions.vue';
|
||||
import BubbleContact from './bubble/Contact.vue';
|
||||
import BubbleFile from './bubble/File.vue';
|
||||
import BubbleImage from './bubble/Image.vue';
|
||||
import BubbleVideo from './bubble/Video.vue';
|
||||
import BubbleImageAudioVideo from './bubble/ImageAudioVideo.vue';
|
||||
import BubbleIntegration from './bubble/Integration.vue';
|
||||
import BubbleLocation from './bubble/Location.vue';
|
||||
import BubbleMailHead from './bubble/MailHead.vue';
|
||||
import BubbleText from './bubble/Text.vue';
|
||||
import BubbleContact from './bubble/Contact.vue';
|
||||
import BubbleReplyTo from './bubble/ReplyTo.vue';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
import BubbleText from './bubble/Text.vue';
|
||||
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu.vue';
|
||||
import instagramImageErrorPlaceholder from './instagramImageErrorPlaceholder.vue';
|
||||
import InstagramStory from './bubble/InstagramStory.vue';
|
||||
import InstagramStoryReply from './bubble/InstagramStoryReply.vue';
|
||||
import Spinner from 'shared/components/Spinner.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import contentTypeMixin from 'shared/mixins/contentTypeMixin';
|
||||
import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
|
||||
@@ -163,19 +152,18 @@ import { LocalStorage } from 'shared/helpers/localStorage';
|
||||
export default {
|
||||
components: {
|
||||
BubbleActions,
|
||||
BubbleContact,
|
||||
BubbleFile,
|
||||
BubbleImage,
|
||||
BubbleVideo,
|
||||
BubbleImageAudioVideo,
|
||||
BubbleIntegration,
|
||||
BubbleLocation,
|
||||
BubbleMailHead,
|
||||
BubbleText,
|
||||
BubbleContact,
|
||||
BubbleReplyTo,
|
||||
BubbleText,
|
||||
ContextMenu,
|
||||
InstagramStory,
|
||||
InstagramStoryReply,
|
||||
Spinner,
|
||||
instagramImageErrorPlaceholder,
|
||||
},
|
||||
mixins: [alertMixin, messageFormatterMixin, contentTypeMixin],
|
||||
props: {
|
||||
@@ -191,10 +179,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
hasInstagramStory: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isWebWidgetInbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -211,10 +195,9 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showContextMenu: false,
|
||||
hasImageError: false,
|
||||
hasMediaLoadError: false,
|
||||
contextMenuPosition: {},
|
||||
showBackgroundHighlight: false,
|
||||
hasImgStoryError: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -290,6 +273,9 @@ export default {
|
||||
// since old messages are only loaded when the user scrolls up
|
||||
return this.data.content_attributes?.in_reply_to;
|
||||
},
|
||||
isAnInstagramStory() {
|
||||
return this.contentAttributes.image_type === 'story_mention';
|
||||
},
|
||||
contextMenuEnabledOptions() {
|
||||
return {
|
||||
copy: this.hasText,
|
||||
@@ -302,7 +288,7 @@ export default {
|
||||
return this.data.content_attributes || {};
|
||||
},
|
||||
externalError() {
|
||||
return this.contentAttributes.external_error || null;
|
||||
return this.contentAttributes.external_error || '';
|
||||
},
|
||||
sender() {
|
||||
return this.data.sender || {};
|
||||
@@ -319,9 +305,6 @@ export default {
|
||||
storyUrl() {
|
||||
return this.contentAttributes.story_url || null;
|
||||
},
|
||||
storyReply() {
|
||||
return this.storyUrl && this.hasInstagramStory;
|
||||
},
|
||||
contentType() {
|
||||
const {
|
||||
data: { content_type: contentType },
|
||||
@@ -402,7 +385,7 @@ export default {
|
||||
return false;
|
||||
}
|
||||
if (this.isFailed) {
|
||||
return this.externalError ? '' : this.$t(`CONVERSATION.SEND_FAILED`);
|
||||
return this.externalError || this.$t(`CONVERSATION.SEND_FAILED`);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
@@ -460,13 +443,11 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
data() {
|
||||
this.hasImageError = false;
|
||||
this.hasImgStoryError = false;
|
||||
this.hasMediaLoadError = false;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.hasImageError = false;
|
||||
this.hasImgStoryError = false;
|
||||
this.hasMediaLoadError = false;
|
||||
bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
|
||||
this.setupHighlightTimer();
|
||||
},
|
||||
@@ -476,13 +457,13 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
isAttachmentImageVideoAudio(fileType) {
|
||||
return ['image', 'audio', 'video'].includes(fileType);
|
||||
return ['image', 'audio', 'video', 'story_mention'].includes(fileType);
|
||||
},
|
||||
hasMediaAttachment(type) {
|
||||
if (this.hasAttachments && this.data.attachments.length > 0) {
|
||||
const { attachments = [{}] } = this.data;
|
||||
const { file_type: fileType } = attachments[0];
|
||||
return fileType === type && !this.hasImageError;
|
||||
return fileType === type && !this.hasMediaLoadError;
|
||||
}
|
||||
if (this.storyReply) {
|
||||
return true;
|
||||
@@ -495,11 +476,8 @@ export default {
|
||||
async retrySendMessage() {
|
||||
await this.$store.dispatch('sendMessageWithData', this.data);
|
||||
},
|
||||
onImageLoadError() {
|
||||
this.hasImageError = true;
|
||||
},
|
||||
onStoryLoadError() {
|
||||
this.hasImgStoryError = true;
|
||||
onMediaLoadError() {
|
||||
this.hasMediaLoadError = true;
|
||||
},
|
||||
openContextMenu(e) {
|
||||
const shouldSkipContextMenu =
|
||||
@@ -731,8 +709,4 @@ li.right {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.story-reply-quote {
|
||||
@apply mt-2 mx-4 mb-0 px-2 pb-0 pt-2 border-l-4 border-solid border-slate-75 dark:border-slate-600 text-slate-600 dark:text-slate-200;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
:data="message"
|
||||
:is-a-tweet="isATweet"
|
||||
:is-a-whatsapp-channel="isAWhatsAppChannel"
|
||||
:has-instagram-story="hasInstagramStory"
|
||||
:is-web-widget-inbox="isAWebWidgetInbox"
|
||||
:inbox-supports-reply-to="inboxSupportsReplyTo"
|
||||
:in-reply-to="getInReplyToMessage(message)"
|
||||
@@ -54,7 +53,6 @@
|
||||
:data="message"
|
||||
:is-a-tweet="isATweet"
|
||||
:is-a-whatsapp-channel="isAWhatsAppChannel"
|
||||
:has-instagram-story="hasInstagramStory"
|
||||
:is-web-widget-inbox="isAWebWidgetInbox"
|
||||
:inbox-supports-reply-to="inboxSupportsReplyTo"
|
||||
:in-reply-to="getInReplyToMessage(message)"
|
||||
@@ -238,10 +236,6 @@ export default {
|
||||
isATweet() {
|
||||
return this.conversationType === 'tweet';
|
||||
},
|
||||
|
||||
hasInstagramStory() {
|
||||
return this.conversationType === 'instagram_direct_message';
|
||||
},
|
||||
isRightOrLeftIcon() {
|
||||
if (this.isContactPanelOpen) {
|
||||
return 'arrow-chevron-right';
|
||||
|
||||
@@ -114,10 +114,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
hasInstagramStory: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
messageType: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="image message-text__wrap">
|
||||
<img :src="url" @click="onClick" @error="onImgError()" />
|
||||
<img :src="url" @click="onClick" @error="$emit('error')" />
|
||||
<woot-modal :full-width="true" :show.sync="show" :on-close="onClose">
|
||||
<img :src="url" class="modal-image skip-context-menu" />
|
||||
</woot-modal>
|
||||
@@ -28,9 +28,6 @@ export default {
|
||||
onClick() {
|
||||
this.show = true;
|
||||
},
|
||||
onImgError() {
|
||||
this.$emit('error');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
v-if="isImage && !isImageError"
|
||||
:src="attachment.data_url"
|
||||
@click="onClick"
|
||||
@error="onImgError()"
|
||||
@error="onImgError"
|
||||
/>
|
||||
<video
|
||||
v-if="isVideo"
|
||||
:src="attachment.data_url"
|
||||
muted
|
||||
playsInline
|
||||
@error="onImgError"
|
||||
@click="onClick"
|
||||
/>
|
||||
<audio v-else-if="isAudio" controls class="skip-context-menu">
|
||||
@@ -21,7 +22,7 @@
|
||||
:show.sync="show"
|
||||
:attachment="attachment"
|
||||
:all-attachments="filteredCurrentChatAttachments"
|
||||
@error="onImgError()"
|
||||
@error="onImgError"
|
||||
@close="onClose"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<bubble-image
|
||||
v-if="!hasImgStoryError"
|
||||
:url="storyUrl"
|
||||
@error="onImageLoadError"
|
||||
/>
|
||||
<bubble-video
|
||||
v-else-if="!hasVideoStoryError"
|
||||
:url="storyUrl"
|
||||
@error="onVideoLoadError"
|
||||
/>
|
||||
<instagram-story-error-place-holder v-else />
|
||||
</template>
|
||||
<script>
|
||||
import BubbleImage from './Image.vue';
|
||||
import BubbleVideo from './Video.vue';
|
||||
import InstagramStoryErrorPlaceHolder from './InstagramStoryErrorPlaceHolder.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BubbleImage,
|
||||
BubbleVideo,
|
||||
InstagramStoryErrorPlaceHolder,
|
||||
},
|
||||
props: {
|
||||
storyUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasImgStoryError: false,
|
||||
hasVideoStoryError: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onImageLoadError() {
|
||||
this.hasImgStoryError = true;
|
||||
this.emitError();
|
||||
},
|
||||
onVideoLoadError() {
|
||||
this.hasVideoStoryError = true;
|
||||
this.emitError();
|
||||
},
|
||||
emitError() {
|
||||
this.$emit('error');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center justify-center px-8 h-28 w-full bg-slate-100 text-slate-700 dark:bg-slate-500 dark:text-slate-75"
|
||||
>
|
||||
<fluent-icon icon="document-error" size="32" />
|
||||
<p class="mb-0 text-slate-700 dark:text-slate-75">
|
||||
{{ $t('COMPONENTS.FILE_BUBBLE.INSTAGRAM_STORY_UNAVAILABLE') }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<blockquote
|
||||
class="my-0 px-2 pb-0 pt-0 border-l-4 border-solid border-slate-75 dark:border-slate-600 text-slate-600 dark:text-slate-200"
|
||||
>
|
||||
<span>{{ $t('CONVERSATION.REPLIED_TO_STORY') }}</span>
|
||||
<instagram-story :story-url="storyUrl" class="mt-3 rounded-md" />
|
||||
</blockquote>
|
||||
</template>
|
||||
<script>
|
||||
import InstagramStory from './InstagramStory.vue';
|
||||
|
||||
export default {
|
||||
components: { InstagramStory },
|
||||
props: {
|
||||
storyUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hasImgStoryError: false,
|
||||
hasVideoStoryError: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onImageLoadError() {
|
||||
this.hasImgStoryError = true;
|
||||
},
|
||||
onVideoLoadError() {
|
||||
this.hasVideoStoryError = true;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="video message-text__wrap">
|
||||
<video :src="url" muted playsInline @click="onClick" />
|
||||
<video ref="videoElement" :src="url" muted playsInline @click="onClick" />
|
||||
<woot-modal :show.sync="show" :on-close="onClose">
|
||||
<video
|
||||
:src="url"
|
||||
controls
|
||||
playsInline
|
||||
class="modal-video skip-context-menu"
|
||||
class="modal-video skip-context-menu mx-auto"
|
||||
/>
|
||||
</woot-modal>
|
||||
</div>
|
||||
@@ -25,6 +25,11 @@ export default {
|
||||
show: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.videoElement.onerror = () => {
|
||||
this.$emit('error');
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.show = false;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<template>
|
||||
<div class="image-placeholder">
|
||||
<fluent-icon icon="document-error" size="32" />
|
||||
<p>{{ $t('COMPONENTS.FILE_BUBBLE.INSTAGRAM_STORY_UNAVAILABLE') }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.image-placeholder {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: var(--space-slab);
|
||||
height: calc(var(--space-large) * 10);
|
||||
margin-top: var(--space-one);
|
||||
width: 100%;
|
||||
background-color: var(--s-75);
|
||||
color: var(--s-800);
|
||||
border-radius: var(--border-radius-normal);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user