feat: signature preview and fix sending signature on whatsapp cloud channel (#183)
* fix: send signature on whatsapp cloud provider * fix: simplify attachment checks and remove redundant comments in ReplyBox * feat: signature preview * fix: update default signature position to top in Editor and ReplyBox components * fix: refactor signature application logic in ReplyBox component
This commit is contained in:
parent
4db3c7c7ed
commit
43d7642485
@ -24,6 +24,7 @@ import { useTrack } from 'dashboard/composables';
|
|||||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import { useMapGetter } from 'dashboard/composables/store';
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
|
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
|
||||||
|
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
import { CONVERSATION_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
import { CONVERSATION_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||||
@ -47,7 +48,6 @@ import {
|
|||||||
import {
|
import {
|
||||||
findNodeToInsertImage,
|
findNodeToInsertImage,
|
||||||
getContentNode,
|
getContentNode,
|
||||||
cleanSignature,
|
|
||||||
insertAtCursor,
|
insertAtCursor,
|
||||||
scrollCursorIntoView,
|
scrollCursorIntoView,
|
||||||
setURLWithQueryAndSize,
|
setURLWithQueryAndSize,
|
||||||
@ -146,6 +146,8 @@ const createState = (content, placeholder, plugins = [], methods = {}) => {
|
|||||||
const { isEditorHotKeyEnabled, fetchSignatureFlagFromUISettings } =
|
const { isEditorHotKeyEnabled, fetchSignatureFlagFromUISettings } =
|
||||||
useUISettings();
|
useUISettings();
|
||||||
|
|
||||||
|
const { formatMessage } = useMessageFormatter();
|
||||||
|
|
||||||
const currentUser = useMapGetter('getCurrentUser');
|
const currentUser = useMapGetter('getCurrentUser');
|
||||||
|
|
||||||
const typingIndicator = createTypingIndicator(
|
const typingIndicator = createTypingIndicator(
|
||||||
@ -273,8 +275,7 @@ const plugins = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const sendWithSignature = computed(() => {
|
const sendWithSignature = computed(() => {
|
||||||
// this is considered the source of truth, we watch this property
|
// this is considered the source of truth for signature display
|
||||||
// on change, we toggle the signature in the editor
|
|
||||||
if (props.allowSignature && !props.isPrivate && props.channelType) {
|
if (props.allowSignature && !props.isPrivate && props.channelType) {
|
||||||
return fetchSignatureFlagFromUISettings(props.channelType);
|
return fetchSignatureFlagFromUISettings(props.channelType);
|
||||||
}
|
}
|
||||||
@ -282,6 +283,23 @@ const sendWithSignature = computed(() => {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const signaturePosition = computed(() => {
|
||||||
|
return currentUser.value?.ui_settings?.signature_position || 'top';
|
||||||
|
});
|
||||||
|
|
||||||
|
const signatureSeparator = computed(() => {
|
||||||
|
return currentUser.value?.ui_settings?.signature_separator || 'blank';
|
||||||
|
});
|
||||||
|
|
||||||
|
const shouldShowSignaturePreview = computed(() => {
|
||||||
|
return sendWithSignature.value && props.signature;
|
||||||
|
});
|
||||||
|
|
||||||
|
const formattedSignature = computed(() => {
|
||||||
|
if (!props.signature) return '';
|
||||||
|
return formatMessage(props.signature, false, false);
|
||||||
|
});
|
||||||
|
|
||||||
watch(showUserMentions, updatedValue => {
|
watch(showUserMentions, updatedValue => {
|
||||||
emit('toggleUserMention', props.isPrivate && updatedValue);
|
emit('toggleUserMention', props.isPrivate && updatedValue);
|
||||||
});
|
});
|
||||||
@ -298,27 +316,10 @@ watch(showToolsMenu, updatedValue => {
|
|||||||
function focusEditorInputField(pos = 'end') {
|
function focusEditorInputField(pos = 'end') {
|
||||||
const { tr } = editorView.state;
|
const { tr } = editorView.state;
|
||||||
|
|
||||||
// Check if signature is at start and adjust cursor position accordingly
|
// Signature is now displayed as read-only preview outside the editor,
|
||||||
const signaturePosition =
|
// so cursor positioning is straightforward
|
||||||
currentUser.value?.ui_settings?.signature_position || 'top';
|
const selection =
|
||||||
const hasSignature = sendWithSignature.value && props.signature;
|
pos === 'end' ? Selection.atEnd(tr.doc) : Selection.atStart(tr.doc);
|
||||||
|
|
||||||
let selection;
|
|
||||||
if (pos === 'end' || !hasSignature || signaturePosition !== 'top') {
|
|
||||||
selection =
|
|
||||||
pos === 'end' ? Selection.atEnd(tr.doc) : Selection.atStart(tr.doc);
|
|
||||||
} else {
|
|
||||||
// Position cursor after signature when signature is at start
|
|
||||||
const signatureLength = props.signature
|
|
||||||
? cleanSignature(props.signature).length
|
|
||||||
: 0;
|
|
||||||
const separatorLength =
|
|
||||||
currentUser.value?.ui_settings?.signature_separator === '--' ? 6 : 2; // "\n--\n" vs "\n\n"
|
|
||||||
const cursorPos = signatureLength + separatorLength;
|
|
||||||
selection = Selection.near(
|
|
||||||
tr.doc.resolve(Math.min(cursorPos, tr.doc.content.size))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
editorView.dispatch(tr.setSelection(selection));
|
editorView.dispatch(tr.setSelection(selection));
|
||||||
editorView.focus();
|
editorView.focus();
|
||||||
@ -765,7 +766,33 @@ useEmitter(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, insertContentIntoEditor);
|
|||||||
hidden
|
hidden
|
||||||
@change="onFileChange"
|
@change="onFileChange"
|
||||||
/>
|
/>
|
||||||
|
<!-- Signature preview at top -->
|
||||||
|
<div
|
||||||
|
v-if="shouldShowSignaturePreview && signaturePosition === 'top'"
|
||||||
|
class="signature-preview signature-preview--top"
|
||||||
|
>
|
||||||
|
<div class="signature-label">
|
||||||
|
{{ t('CONVERSATION.FOOTER.SIGNATURE_LABEL_TOP') }}
|
||||||
|
</div>
|
||||||
|
<div v-dompurify-html="formattedSignature" class="signature-content" />
|
||||||
|
<div v-if="signatureSeparator === '--'" class="signature-separator">
|
||||||
|
{{ signatureSeparator }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div ref="editor" />
|
<div ref="editor" />
|
||||||
|
<!-- Signature preview at bottom -->
|
||||||
|
<div
|
||||||
|
v-if="shouldShowSignaturePreview && signaturePosition === 'bottom'"
|
||||||
|
class="signature-preview signature-preview--bottom"
|
||||||
|
>
|
||||||
|
<div class="signature-label">
|
||||||
|
{{ t('CONVERSATION.FOOTER.SIGNATURE_LABEL_BOTTOM') }}
|
||||||
|
</div>
|
||||||
|
<div v-if="signatureSeparator === '--'" class="signature-separator">
|
||||||
|
{{ signatureSeparator }}
|
||||||
|
</div>
|
||||||
|
<div v-dompurify-html="formattedSignature" class="signature-content" />
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="isImageNodeSelected && showImageResizeToolbar"
|
v-show="isImageNodeSelected && showImageResizeToolbar"
|
||||||
class="absolute shadow-md rounded-[6px] flex gap-1 py-1 px-1 bg-n-solid-3 outline outline-1 outline-n-weak text-n-slate-12"
|
class="absolute shadow-md rounded-[6px] flex gap-1 py-1 px-1 bg-n-solid-3 outline outline-1 outline-n-weak text-n-slate-12"
|
||||||
@ -790,6 +817,42 @@ useEmitter(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, insertContentIntoEditor);
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '@chatwoot/prosemirror-schema/src/styles/base.scss';
|
@import '@chatwoot/prosemirror-schema/src/styles/base.scss';
|
||||||
|
|
||||||
|
.signature-preview {
|
||||||
|
@apply px-1 py-1 text-n-slate-10 text-sm pointer-events-none select-none opacity-70;
|
||||||
|
|
||||||
|
&--top {
|
||||||
|
@apply border-b border-n-weak pb-1;
|
||||||
|
|
||||||
|
.signature-separator {
|
||||||
|
@apply text-n-slate-9 mt-1 mb-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bottom {
|
||||||
|
@apply border-t border-n-weak pt-1 mt-2;
|
||||||
|
|
||||||
|
.signature-separator {
|
||||||
|
@apply text-n-slate-9 mb-1 mt-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.signature-label {
|
||||||
|
@apply text-xs text-n-slate-9 mb-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signature-content {
|
||||||
|
@apply break-words;
|
||||||
|
|
||||||
|
:deep(p) {
|
||||||
|
@apply m-0 text-n-slate-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(a) {
|
||||||
|
@apply text-n-slate-10 no-underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ProseMirror-menubar-wrapper {
|
.ProseMirror-menubar-wrapper {
|
||||||
@apply flex flex-col gap-3;
|
@apply flex flex-col gap-3;
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { mapGetters } from 'vuex';
|
|||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||||
import { useTrack } from 'dashboard/composables';
|
import { useTrack } from 'dashboard/composables';
|
||||||
|
import { useMessageFormatter } from 'shared/composables/useMessageFormatter';
|
||||||
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
import keyboardEventListenerMixins from 'shared/mixins/keyboardEventListenerMixins';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
|
|
||||||
@ -42,12 +43,7 @@ import {
|
|||||||
} from 'dashboard/helper/quotedEmailHelper';
|
} from 'dashboard/helper/quotedEmailHelper';
|
||||||
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
|
||||||
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
|
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
|
||||||
import {
|
import { appendSignature } from 'dashboard/helper/editorHelper';
|
||||||
appendSignature,
|
|
||||||
removeSignature,
|
|
||||||
getEffectiveChannelType,
|
|
||||||
extractTextFromMarkdown,
|
|
||||||
} from 'dashboard/helper/editorHelper';
|
|
||||||
|
|
||||||
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
|
import { LOCAL_STORAGE_KEYS } from 'dashboard/constants/localStorage';
|
||||||
import { LocalStorage } from 'shared/helpers/localStorage';
|
import { LocalStorage } from 'shared/helpers/localStorage';
|
||||||
@ -92,6 +88,8 @@ export default {
|
|||||||
fetchQuotedReplyFlagFromUISettings,
|
fetchQuotedReplyFlagFromUISettings,
|
||||||
} = useUISettings();
|
} = useUISettings();
|
||||||
|
|
||||||
|
const { formatMessage } = useMessageFormatter();
|
||||||
|
|
||||||
const replyEditor = useTemplateRef('replyEditor');
|
const replyEditor = useTemplateRef('replyEditor');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -101,6 +99,7 @@ export default {
|
|||||||
setQuotedReplyFlagForInbox,
|
setQuotedReplyFlagForInbox,
|
||||||
fetchQuotedReplyFlagFromUISettings,
|
fetchQuotedReplyFlagFromUISettings,
|
||||||
replyEditor,
|
replyEditor,
|
||||||
|
formatMessage,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -418,11 +417,24 @@ export default {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
// ensure that the signature is plain text depending on `showRichContentEditor`
|
// Signature preview for non-rich editor (WhatsApp, etc.)
|
||||||
signatureToApply() {
|
shouldShowSignaturePreview() {
|
||||||
return this.showRichContentEditor
|
return (
|
||||||
? this.messageSignature
|
this.sendWithSignature &&
|
||||||
: extractTextFromMarkdown(this.messageSignature);
|
this.messageSignature &&
|
||||||
|
!this.isPrivate &&
|
||||||
|
!this.showRichContentEditor
|
||||||
|
);
|
||||||
|
},
|
||||||
|
signaturePosition() {
|
||||||
|
return this.currentUser?.ui_settings?.signature_position || 'top';
|
||||||
|
},
|
||||||
|
signatureSeparator() {
|
||||||
|
return this.currentUser?.ui_settings?.signature_separator || 'blank';
|
||||||
|
},
|
||||||
|
formattedSignature() {
|
||||||
|
if (!this.messageSignature) return '';
|
||||||
|
return this.formatMessage(this.messageSignature, false, false);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -606,31 +618,6 @@ export default {
|
|||||||
this.message = messageFromStore;
|
this.message = messageFromStore;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleSignatureForDraft(message) {
|
|
||||||
if (this.isPrivate) {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
if (this.showRichContentEditor) {
|
|
||||||
const effectiveChannelType = getEffectiveChannelType(
|
|
||||||
this.channelType,
|
|
||||||
this.inbox?.medium || ''
|
|
||||||
);
|
|
||||||
return this.sendWithSignature
|
|
||||||
? appendSignature(
|
|
||||||
message,
|
|
||||||
this.messageSignature,
|
|
||||||
effectiveChannelType
|
|
||||||
)
|
|
||||||
: removeSignature(
|
|
||||||
message,
|
|
||||||
this.messageSignature,
|
|
||||||
effectiveChannelType
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.sendWithSignature
|
|
||||||
? appendSignature(message, this.signatureToApply)
|
|
||||||
: removeSignature(message, this.signatureToApply);
|
|
||||||
},
|
|
||||||
removeFromDraft() {
|
removeFromDraft() {
|
||||||
if (this.conversationIdByRoute) {
|
if (this.conversationIdByRoute) {
|
||||||
const key = `draft-${this.conversationIdByRoute}-${this.replyType}`;
|
const key = `draft-${this.conversationIdByRoute}-${this.replyType}`;
|
||||||
@ -686,6 +673,18 @@ export default {
|
|||||||
this.isEditorHotKeyEnabled(selectedKey)
|
this.isEditorHotKeyEnabled(selectedKey)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
applySignatureToMessage(message) {
|
||||||
|
if (!this.sendWithSignature || !this.messageSignature) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
const { signature_position, signature_separator } =
|
||||||
|
this.currentUser?.ui_settings || {};
|
||||||
|
const signatureSettings = {
|
||||||
|
position: signature_position || 'top',
|
||||||
|
separator: signature_separator || 'blank',
|
||||||
|
};
|
||||||
|
return appendSignature(message, this.messageSignature, signatureSettings);
|
||||||
|
},
|
||||||
onPaste(e) {
|
onPaste(e) {
|
||||||
// Don't handle paste if compose new conversation modal is open
|
// Don't handle paste if compose new conversation modal is open
|
||||||
if (this.newConversationModalActive) {
|
if (this.newConversationModalActive) {
|
||||||
@ -999,8 +998,10 @@ export default {
|
|||||||
getMultipleMessagesPayload(message) {
|
getMultipleMessagesPayload(message) {
|
||||||
const multipleMessagePayload = [];
|
const multipleMessagePayload = [];
|
||||||
|
|
||||||
if (this.attachedFiles && this.attachedFiles.length) {
|
const messageWithSignature = this.applySignatureToMessage(message);
|
||||||
let caption = this.isAnInstagramChannel ? '' : message;
|
|
||||||
|
if (this.attachedFiles?.length) {
|
||||||
|
let caption = this.isAnInstagramChannel ? '' : messageWithSignature;
|
||||||
this.attachedFiles.forEach(attachment => {
|
this.attachedFiles.forEach(attachment => {
|
||||||
const attachedFile = this.globalConfig.directUploadsEnabled
|
const attachedFile = this.globalConfig.directUploadsEnabled
|
||||||
? attachment.blobSignedId
|
? attachment.blobSignedId
|
||||||
@ -1020,8 +1021,7 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasNoAttachments =
|
const hasNoAttachments = !this.attachedFiles?.length;
|
||||||
!this.attachedFiles || !this.attachedFiles.length;
|
|
||||||
// For Instagram, we need a separate text message
|
// For Instagram, we need a separate text message
|
||||||
// For WhatsApp, we only need a text message if there are no attachments
|
// For WhatsApp, we only need a text message if there are no attachments
|
||||||
if (
|
if (
|
||||||
@ -1030,7 +1030,7 @@ export default {
|
|||||||
) {
|
) {
|
||||||
let messagePayload = {
|
let messagePayload = {
|
||||||
conversationId: this.currentChat.id,
|
conversationId: this.currentChat.id,
|
||||||
message,
|
message: messageWithSignature,
|
||||||
private: false,
|
private: false,
|
||||||
sender: this.sender,
|
sender: this.sender,
|
||||||
};
|
};
|
||||||
@ -1044,18 +1044,8 @@ export default {
|
|||||||
},
|
},
|
||||||
getMessagePayload(message) {
|
getMessagePayload(message) {
|
||||||
let finalMessage = this.getMessageWithQuotedEmailText(message);
|
let finalMessage = this.getMessageWithQuotedEmailText(message);
|
||||||
if (this.sendWithSignature && !this.isPrivate && this.messageSignature) {
|
if (!this.isPrivate) {
|
||||||
const { signature_position, signature_separator } =
|
finalMessage = this.applySignatureToMessage(finalMessage);
|
||||||
this.currentUser?.ui_settings || {};
|
|
||||||
const signatureSettings = {
|
|
||||||
position: signature_position || 'top',
|
|
||||||
separator: signature_separator || 'blank',
|
|
||||||
};
|
|
||||||
finalMessage = appendSignature(
|
|
||||||
message,
|
|
||||||
this.messageSignature,
|
|
||||||
signatureSettings
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let messagePayload = {
|
let messagePayload = {
|
||||||
@ -1066,7 +1056,7 @@ export default {
|
|||||||
};
|
};
|
||||||
messagePayload = this.setReplyToInPayload(messagePayload);
|
messagePayload = this.setReplyToInPayload(messagePayload);
|
||||||
|
|
||||||
if (this.attachedFiles && this.attachedFiles.length) {
|
if (this.attachedFiles?.length) {
|
||||||
messagePayload.files = [];
|
messagePayload.files = [];
|
||||||
messagePayload.isRecordedAudio = [];
|
messagePayload.isRecordedAudio = [];
|
||||||
this.attachedFiles.forEach(attachment => {
|
this.attachedFiles.forEach(attachment => {
|
||||||
@ -1222,18 +1212,51 @@ export default {
|
|||||||
@play="recordingAudioState = 'playing'"
|
@play="recordingAudioState = 'playing'"
|
||||||
@pause="recordingAudioState = 'paused'"
|
@pause="recordingAudioState = 'paused'"
|
||||||
/>
|
/>
|
||||||
<ResizableTextArea
|
<div v-else-if="!showRichContentEditor" class="w-full">
|
||||||
v-else-if="!showRichContentEditor"
|
<!-- Signature preview at top for non-rich editor -->
|
||||||
ref="messageInput"
|
<div
|
||||||
v-model="message"
|
v-if="shouldShowSignaturePreview && signaturePosition === 'top'"
|
||||||
class="rounded-none input"
|
class="signature-preview px-2 py-1 text-slate-500 dark:text-slate-400 text-sm opacity-70 select-none border-b border-slate-100 dark:border-slate-700"
|
||||||
:placeholder="messagePlaceHolder"
|
>
|
||||||
:min-height="4"
|
<div class="text-xs text-slate-400 dark:text-slate-500 mb-1">
|
||||||
@typing-off="onTypingOff"
|
{{ $t('CONVERSATION.FOOTER.SIGNATURE_LABEL_TOP') }}
|
||||||
@typing-on="onTypingOn"
|
</div>
|
||||||
@focus="onFocus"
|
<div v-dompurify-html="formattedSignature" />
|
||||||
@blur="onBlur"
|
<div
|
||||||
/>
|
v-if="signatureSeparator === '--'"
|
||||||
|
class="text-slate-400 dark:text-slate-500 mt-1"
|
||||||
|
>
|
||||||
|
{{ signatureSeparator }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ResizableTextArea
|
||||||
|
ref="messageInput"
|
||||||
|
v-model="message"
|
||||||
|
class="rounded-none input"
|
||||||
|
:placeholder="messagePlaceHolder"
|
||||||
|
:min-height="4"
|
||||||
|
@typing-off="onTypingOff"
|
||||||
|
@typing-on="onTypingOn"
|
||||||
|
@focus="onFocus"
|
||||||
|
@blur="onBlur"
|
||||||
|
/>
|
||||||
|
<!-- Signature preview at bottom for non-rich editor -->
|
||||||
|
<div
|
||||||
|
v-if="shouldShowSignaturePreview && signaturePosition === 'bottom'"
|
||||||
|
class="signature-preview px-2 py-1 mt-2 text-slate-500 dark:text-slate-400 text-sm opacity-70 select-none border-t border-slate-100 dark:border-slate-700"
|
||||||
|
>
|
||||||
|
<div class="text-xs text-slate-400 dark:text-slate-500 mb-1">
|
||||||
|
{{ $t('CONVERSATION.FOOTER.SIGNATURE_LABEL_BOTTOM') }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="signatureSeparator === '--'"
|
||||||
|
class="text-slate-400 dark:text-slate-500 mb-1"
|
||||||
|
>
|
||||||
|
{{ signatureSeparator }}
|
||||||
|
</div>
|
||||||
|
<div v-dompurify-html="formattedSignature" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<WootMessageEditor
|
<WootMessageEditor
|
||||||
v-else
|
v-else
|
||||||
v-model="message"
|
v-model="message"
|
||||||
@ -1245,6 +1268,8 @@ export default {
|
|||||||
:min-height="4"
|
:min-height="4"
|
||||||
enable-variables
|
enable-variables
|
||||||
:variables="messageVariables"
|
:variables="messageVariables"
|
||||||
|
:signature="messageSignature"
|
||||||
|
allow-signature
|
||||||
:channel-type="channelType"
|
:channel-type="channelType"
|
||||||
:medium="inbox.medium"
|
:medium="inbox.medium"
|
||||||
@typing-off="onTypingOff"
|
@typing-off="onTypingOff"
|
||||||
|
|||||||
@ -184,6 +184,8 @@
|
|||||||
"MESSAGE_SIGN_TOOLTIP": "Message signature",
|
"MESSAGE_SIGN_TOOLTIP": "Message signature",
|
||||||
"ENABLE_SIGN_TOOLTIP": "Enable signature",
|
"ENABLE_SIGN_TOOLTIP": "Enable signature",
|
||||||
"DISABLE_SIGN_TOOLTIP": "Disable signature",
|
"DISABLE_SIGN_TOOLTIP": "Disable signature",
|
||||||
|
"SIGNATURE_LABEL_TOP": "↓ Signature",
|
||||||
|
"SIGNATURE_LABEL_BOTTOM": "↑ Signature",
|
||||||
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.",
|
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.",
|
||||||
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents",
|
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents",
|
||||||
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "Message signature is not configured, please configure it in profile settings.",
|
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "Message signature is not configured, please configure it in profile settings.",
|
||||||
|
|||||||
@ -184,6 +184,8 @@
|
|||||||
"MESSAGE_SIGN_TOOLTIP": "Assinatura de mensagem",
|
"MESSAGE_SIGN_TOOLTIP": "Assinatura de mensagem",
|
||||||
"ENABLE_SIGN_TOOLTIP": "Ativar assinatura",
|
"ENABLE_SIGN_TOOLTIP": "Ativar assinatura",
|
||||||
"DISABLE_SIGN_TOOLTIP": "Desativar assinatura",
|
"DISABLE_SIGN_TOOLTIP": "Desativar assinatura",
|
||||||
|
"SIGNATURE_LABEL_TOP": "↓ Assinatura",
|
||||||
|
"SIGNATURE_LABEL_BOTTOM": "↑ Assinatura",
|
||||||
"MSG_INPUT": "Shift + enter para nova linha. Digite '/' para selecionar uma Resposta Pronta.",
|
"MSG_INPUT": "Shift + enter para nova linha. Digite '/' para selecionar uma Resposta Pronta.",
|
||||||
"PRIVATE_MSG_INPUT": "A mensagem será visível apenas para agentes",
|
"PRIVATE_MSG_INPUT": "A mensagem será visível apenas para agentes",
|
||||||
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "A assinatura da mensagem não está configurada. Por favor, configure-a nas configurações do perfil.",
|
"MESSAGE_SIGNATURE_NOT_CONFIGURED": "A assinatura da mensagem não está configurada. Por favor, configure-a nas configurações do perfil.",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user