feat: Lets users insert connected portal article into replies [CW-2282] (#8117)

- Lets users insert connected portal articles into replies

https://linear.app/chatwoot/issue/CW-2282/list-all-the-top-articles-from-the-connected-help-center
https://linear.app/chatwoot/issue/CW-1453/container-view-for-showing-search-input-and-result-items
This commit is contained in:
Nithin David Thomas
2023-11-04 15:27:25 +05:30
committed by GitHub
parent b4d20689b7
commit 39d0748a5b
14 changed files with 327 additions and 54 deletions

View File

@@ -109,6 +109,16 @@
</h4>
</div>
</transition>
<woot-button
v-if="enableInsertArticleInReply"
v-tooltip.top-end="$t('HELP_CENTER.ARTICLE_SEARCH.OPEN_ARTICLE_SEARCH')"
icon="document-text-link"
color-scheme="secondary"
variant="smooth"
size="small"
:title="$t('HELP_CENTER.ARTICLE_SEARCH.OPEN_ARTICLE_SEARCH')"
@click="toggleInsertArticle"
/>
</div>
<div class="right-wrap">
<woot-button
@@ -233,6 +243,10 @@ export default {
type: Boolean,
default: false,
},
portalSlug: {
type: String,
required: true,
},
},
computed: {
...mapGetters({
@@ -307,6 +321,13 @@ export default {
? this.$t('CONVERSATION.FOOTER.DISABLE_SIGN_TOOLTIP')
: this.$t('CONVERSATION.FOOTER.ENABLE_SIGN_TOOLTIP');
},
enableInsertArticleInReply() {
const isFeatEnabled = this.isFeatureEnabledonAccount(
this.accountId,
FEATURE_FLAGS.INSERT_ARTICLE_IN_REPLY
);
return isFeatEnabled && this.portalSlug;
},
},
mounted() {
ActiveStorage.start();
@@ -325,6 +346,9 @@ export default {
replaceText(text) {
this.$emit('replace-text', text);
},
toggleInsertArticle() {
this.$emit('toggle-insert-article');
},
},
};
</script>

View File

@@ -18,6 +18,12 @@
:popout-reply-box="popoutReplyBox"
@click="$emit('click')"
/>
<article-search-popover
v-if="showArticleSearchPopover && connectedPortalSlug"
:selected-portal-slug="connectedPortalSlug"
@insert="handleInsert"
@close="onSearchPopoverClose"
/>
<div class="reply-box__top">
<reply-to-message
v-if="shouldShowReplyToMessage"
@@ -35,7 +41,7 @@
v-if="showEmojiPicker"
v-on-clickaway="hideEmojiPicker"
:class="emojiDialogClassOnExpandedLayoutAndRTLView"
:on-click="emojiOnClick"
:on-click="addIntoEditor"
/>
<reply-email-head
v-if="showReplyHead"
@@ -121,10 +127,12 @@
:toggle-audio-recorder="toggleAudioRecorder"
:toggle-emoji-picker="toggleEmojiPicker"
:message="message"
:portal-slug="connectedPortalSlug"
:new-conversation-modal-active="newConversationModalActive"
@selectWhatsappTemplate="openWhatsappTemplateModal"
@toggle-editor="toggleRichContentEditor"
@replace-text="replaceText"
@toggle-insert-article="toggleInsertArticle"
/>
<whatsapp-templates
:inbox-id="inbox.id"
@@ -154,6 +162,7 @@ import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview.v
import ReplyTopPanel from 'dashboard/components/widgets/WootWriter/ReplyTopPanel.vue';
import ReplyEmailHead from './ReplyEmailHead.vue';
import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel.vue';
import ArticleSearchPopover from 'dashboard/routes/dashboard/helpcenter/components/ArticleSearch/SearchPopover.vue';
import MessageSignatureMissingAlert from './MessageSignatureMissingAlert';
import Banner from 'dashboard/components/ui/Banner.vue';
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
@@ -206,6 +215,7 @@ export default {
Banner,
WhatsappTemplates,
MessageSignatureMissingAlert,
ArticleSearchPopover,
},
mixins: [
clickaway,
@@ -248,6 +258,7 @@ export default {
showCannedMenu: false,
showVariablesMenu: false,
newConversationModalActive: false,
showArticleSearchPopover: false,
};
},
computed: {
@@ -506,6 +517,11 @@ export default {
? this.messageSignature
: extractTextFromMarkdown(this.messageSignature);
},
connectedPortalSlug() {
const { help_center: portal = {} } = this.inbox;
const { slug = '' } = portal;
return slug;
},
},
watch: {
currentChat(conversation) {
@@ -597,6 +613,23 @@ export default {
);
},
methods: {
handleInsert(article) {
const { url, title } = article;
if (this.isRichEditorEnabled) {
// Removing empty lines from the title
const lines = title.split('\n');
const nonEmptyLines = lines.filter(line => line.trim() !== '');
const filteredMarkdown = nonEmptyLines.join(' ');
bus.$emit(
BUS_EVENTS.INSERT_INTO_RICH_EDITOR,
`[${filteredMarkdown}](${url})`
);
} else {
this.addIntoEditor(
`${this.$t('CONVERSATION.REPLYBOX.INSERT_READ_MORE')} ${url}`
);
}
},
toggleRichContentEditor() {
this.updateUISettings({
display_rich_content_editor: !this.showRichContentEditor,
@@ -862,22 +895,22 @@ export default {
clearEditorSelection() {
this.updateEditorSelectionWith = '';
},
insertEmoji(emoji, selectionStart, selectionEnd) {
insertIntoTextEditor(text, selectionStart, selectionEnd) {
const { message } = this;
const newMessage =
message.slice(0, selectionStart) +
emoji +
text +
message.slice(selectionEnd, message.length);
this.message = newMessage;
},
emojiOnClick(emoji) {
addIntoEditor(content) {
if (this.showRichContentEditor) {
this.updateEditorSelectionWith = emoji;
this.updateEditorSelectionWith = content;
this.onFocus();
}
if (!this.showRichContentEditor) {
const { selectionStart, selectionEnd } = this.$refs.messageInput.$el;
this.insertEmoji(emoji, selectionStart, selectionEnd);
this.insertIntoTextEditor(content, selectionStart, selectionEnd);
}
},
clearMessage() {
@@ -1136,6 +1169,12 @@ export default {
// When new conversation modal is open
this.newConversationModalActive = isActive;
},
onSearchPopoverClose() {
this.showArticleSearchPopover = false;
},
toggleInsertArticle() {
this.showArticleSearchPopover = !this.showArticleSearchPopover;
},
},
};
</script>
@@ -1154,7 +1193,7 @@ export default {
}
.reply-box {
@apply border-t border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-900;
@apply relative border-t border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-900;
&.is-private {
@apply bg-yellow-50 dark:bg-yellow-200;