fix: Update Instagram story rendering (#8240)

This commit is contained in:
Pranav Raj S
2023-10-30 11:16:14 -07:00
committed by GitHub
parent dfba4770bd
commit 2ba81830f3
10 changed files with 140 additions and 99 deletions

View File

@@ -22,18 +22,7 @@
:bcc="emailHeadAttributes.bcc" :bcc="emailHeadAttributes.bcc"
:is-incoming="isIncoming" :is-incoming="isIncoming"
/> />
<blockquote v-if="storyReply" class="story-reply-quote"> <instagram-story-reply v-if="storyUrl" :story-url="storyUrl" />
<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>
<bubble-reply-to <bubble-reply-to
v-if="inReplyToMessageId && inboxSupportsReplyTo" v-if="inReplyToMessageId && inboxSupportsReplyTo"
:message="inReplyTo" :message="inReplyTo"
@@ -59,10 +48,15 @@
</span> </span>
<div v-if="!isPending && hasAttachments"> <div v-if="!isPending && hasAttachments">
<div v-for="attachment in attachments" :key="attachment.id"> <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 <bubble-image-audio-video
v-if="isAttachmentImageVideoAudio(attachment.file_type)" v-else-if="isAttachmentImageVideoAudio(attachment.file_type)"
:attachment="attachment" :attachment="attachment"
@error="onImageLoadError" @error="onMediaLoadError"
/> />
<bubble-location <bubble-location
v-else-if="attachment.file_type === 'location'" v-else-if="attachment.file_type === 'location'"
@@ -75,9 +69,6 @@
:name="data.content" :name="data.content"
:phone-number="attachment.fallback_title" :phone-number="attachment.fallback_title"
/> />
<instagram-image-error-placeholder
v-else-if="hasImageError && hasInstagramStory"
/>
<bubble-file v-else :url="attachment.data_url" /> <bubble-file v-else :url="attachment.data_url" />
</div> </div>
</div> </div>
@@ -89,7 +80,6 @@
:story-id="`${storyId}`" :story-id="`${storyId}`"
:is-a-tweet="isATweet" :is-a-tweet="isATweet"
:is-a-whatsapp-channel="isAWhatsAppChannel" :is-a-whatsapp-channel="isAWhatsAppChannel"
:has-instagram-story="hasInstagramStory"
:is-email="isEmailContentType" :is-email="isEmailContentType"
:is-private="data.private" :is-private="data.private"
:message-type="data.message_type" :message-type="data.message_type"
@@ -138,19 +128,18 @@
<script> <script>
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import BubbleActions from './bubble/Actions.vue'; import BubbleActions from './bubble/Actions.vue';
import BubbleContact from './bubble/Contact.vue';
import BubbleFile from './bubble/File.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 BubbleImageAudioVideo from './bubble/ImageAudioVideo.vue';
import BubbleIntegration from './bubble/Integration.vue'; import BubbleIntegration from './bubble/Integration.vue';
import BubbleLocation from './bubble/Location.vue'; import BubbleLocation from './bubble/Location.vue';
import BubbleMailHead from './bubble/MailHead.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 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 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 alertMixin from 'shared/mixins/alertMixin';
import contentTypeMixin from 'shared/mixins/contentTypeMixin'; import contentTypeMixin from 'shared/mixins/contentTypeMixin';
import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages'; import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
@@ -163,19 +152,18 @@ import { LocalStorage } from 'shared/helpers/localStorage';
export default { export default {
components: { components: {
BubbleActions, BubbleActions,
BubbleContact,
BubbleFile, BubbleFile,
BubbleImage,
BubbleVideo,
BubbleImageAudioVideo, BubbleImageAudioVideo,
BubbleIntegration, BubbleIntegration,
BubbleLocation, BubbleLocation,
BubbleMailHead, BubbleMailHead,
BubbleText,
BubbleContact,
BubbleReplyTo, BubbleReplyTo,
BubbleText,
ContextMenu, ContextMenu,
InstagramStory,
InstagramStoryReply,
Spinner, Spinner,
instagramImageErrorPlaceholder,
}, },
mixins: [alertMixin, messageFormatterMixin, contentTypeMixin], mixins: [alertMixin, messageFormatterMixin, contentTypeMixin],
props: { props: {
@@ -191,10 +179,6 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
hasInstagramStory: {
type: Boolean,
default: false,
},
isWebWidgetInbox: { isWebWidgetInbox: {
type: Boolean, type: Boolean,
default: false, default: false,
@@ -211,10 +195,9 @@ export default {
data() { data() {
return { return {
showContextMenu: false, showContextMenu: false,
hasImageError: false, hasMediaLoadError: false,
contextMenuPosition: {}, contextMenuPosition: {},
showBackgroundHighlight: false, showBackgroundHighlight: false,
hasImgStoryError: false,
}; };
}, },
computed: { computed: {
@@ -290,6 +273,9 @@ export default {
// since old messages are only loaded when the user scrolls up // since old messages are only loaded when the user scrolls up
return this.data.content_attributes?.in_reply_to; return this.data.content_attributes?.in_reply_to;
}, },
isAnInstagramStory() {
return this.contentAttributes.image_type === 'story_mention';
},
contextMenuEnabledOptions() { contextMenuEnabledOptions() {
return { return {
copy: this.hasText, copy: this.hasText,
@@ -302,7 +288,7 @@ export default {
return this.data.content_attributes || {}; return this.data.content_attributes || {};
}, },
externalError() { externalError() {
return this.contentAttributes.external_error || null; return this.contentAttributes.external_error || '';
}, },
sender() { sender() {
return this.data.sender || {}; return this.data.sender || {};
@@ -319,9 +305,6 @@ export default {
storyUrl() { storyUrl() {
return this.contentAttributes.story_url || null; return this.contentAttributes.story_url || null;
}, },
storyReply() {
return this.storyUrl && this.hasInstagramStory;
},
contentType() { contentType() {
const { const {
data: { content_type: contentType }, data: { content_type: contentType },
@@ -402,7 +385,7 @@ export default {
return false; return false;
} }
if (this.isFailed) { if (this.isFailed) {
return this.externalError ? '' : this.$t(`CONVERSATION.SEND_FAILED`); return this.externalError || this.$t(`CONVERSATION.SEND_FAILED`);
} }
return false; return false;
}, },
@@ -460,13 +443,11 @@ export default {
}, },
watch: { watch: {
data() { data() {
this.hasImageError = false; this.hasMediaLoadError = false;
this.hasImgStoryError = false;
}, },
}, },
mounted() { mounted() {
this.hasImageError = false; this.hasMediaLoadError = false;
this.hasImgStoryError = false;
bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu); bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
this.setupHighlightTimer(); this.setupHighlightTimer();
}, },
@@ -476,13 +457,13 @@ export default {
}, },
methods: { methods: {
isAttachmentImageVideoAudio(fileType) { isAttachmentImageVideoAudio(fileType) {
return ['image', 'audio', 'video'].includes(fileType); return ['image', 'audio', 'video', 'story_mention'].includes(fileType);
}, },
hasMediaAttachment(type) { hasMediaAttachment(type) {
if (this.hasAttachments && this.data.attachments.length > 0) { if (this.hasAttachments && this.data.attachments.length > 0) {
const { attachments = [{}] } = this.data; const { attachments = [{}] } = this.data;
const { file_type: fileType } = attachments[0]; const { file_type: fileType } = attachments[0];
return fileType === type && !this.hasImageError; return fileType === type && !this.hasMediaLoadError;
} }
if (this.storyReply) { if (this.storyReply) {
return true; return true;
@@ -495,11 +476,8 @@ export default {
async retrySendMessage() { async retrySendMessage() {
await this.$store.dispatch('sendMessageWithData', this.data); await this.$store.dispatch('sendMessageWithData', this.data);
}, },
onImageLoadError() { onMediaLoadError() {
this.hasImageError = true; this.hasMediaLoadError = true;
},
onStoryLoadError() {
this.hasImgStoryError = true;
}, },
openContextMenu(e) { openContextMenu(e) {
const shouldSkipContextMenu = 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> </style>

View File

@@ -31,7 +31,6 @@
:data="message" :data="message"
:is-a-tweet="isATweet" :is-a-tweet="isATweet"
:is-a-whatsapp-channel="isAWhatsAppChannel" :is-a-whatsapp-channel="isAWhatsAppChannel"
:has-instagram-story="hasInstagramStory"
:is-web-widget-inbox="isAWebWidgetInbox" :is-web-widget-inbox="isAWebWidgetInbox"
:inbox-supports-reply-to="inboxSupportsReplyTo" :inbox-supports-reply-to="inboxSupportsReplyTo"
:in-reply-to="getInReplyToMessage(message)" :in-reply-to="getInReplyToMessage(message)"
@@ -54,7 +53,6 @@
:data="message" :data="message"
:is-a-tweet="isATweet" :is-a-tweet="isATweet"
:is-a-whatsapp-channel="isAWhatsAppChannel" :is-a-whatsapp-channel="isAWhatsAppChannel"
:has-instagram-story="hasInstagramStory"
:is-web-widget-inbox="isAWebWidgetInbox" :is-web-widget-inbox="isAWebWidgetInbox"
:inbox-supports-reply-to="inboxSupportsReplyTo" :inbox-supports-reply-to="inboxSupportsReplyTo"
:in-reply-to="getInReplyToMessage(message)" :in-reply-to="getInReplyToMessage(message)"
@@ -238,10 +236,6 @@ export default {
isATweet() { isATweet() {
return this.conversationType === 'tweet'; return this.conversationType === 'tweet';
}, },
hasInstagramStory() {
return this.conversationType === 'instagram_direct_message';
},
isRightOrLeftIcon() { isRightOrLeftIcon() {
if (this.isContactPanelOpen) { if (this.isContactPanelOpen) {
return 'arrow-chevron-right'; return 'arrow-chevron-right';

View File

@@ -114,10 +114,6 @@ export default {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
hasInstagramStory: {
type: Boolean,
default: true,
},
messageType: { messageType: {
type: Number, type: Number,
default: 1, default: 1,

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="image message-text__wrap"> <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"> <woot-modal :full-width="true" :show.sync="show" :on-close="onClose">
<img :src="url" class="modal-image skip-context-menu" /> <img :src="url" class="modal-image skip-context-menu" />
</woot-modal> </woot-modal>
@@ -28,9 +28,6 @@ export default {
onClick() { onClick() {
this.show = true; this.show = true;
}, },
onImgError() {
this.$emit('error');
},
}, },
}; };
</script> </script>

View File

@@ -4,13 +4,14 @@
v-if="isImage && !isImageError" v-if="isImage && !isImageError"
:src="attachment.data_url" :src="attachment.data_url"
@click="onClick" @click="onClick"
@error="onImgError()" @error="onImgError"
/> />
<video <video
v-if="isVideo" v-if="isVideo"
:src="attachment.data_url" :src="attachment.data_url"
muted muted
playsInline playsInline
@error="onImgError"
@click="onClick" @click="onClick"
/> />
<audio v-else-if="isAudio" controls class="skip-context-menu"> <audio v-else-if="isAudio" controls class="skip-context-menu">
@@ -21,7 +22,7 @@
:show.sync="show" :show.sync="show"
:attachment="attachment" :attachment="attachment"
:all-attachments="filteredCurrentChatAttachments" :all-attachments="filteredCurrentChatAttachments"
@error="onImgError()" @error="onImgError"
@close="onClose" @close="onClose"
/> />
</div> </div>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -1,12 +1,12 @@
<template> <template>
<div class="video message-text__wrap"> <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"> <woot-modal :show.sync="show" :on-close="onClose">
<video <video
:src="url" :src="url"
controls controls
playsInline playsInline
class="modal-video skip-context-menu" class="modal-video skip-context-menu mx-auto"
/> />
</woot-modal> </woot-modal>
</div> </div>
@@ -25,6 +25,11 @@ export default {
show: false, show: false,
}; };
}, },
mounted() {
this.$refs.videoElement.onerror = () => {
this.$emit('error');
};
},
methods: { methods: {
onClose() { onClose() {
this.show = false; this.show = false;

View File

@@ -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>