Merge branch 'develop' into deploy-apr-15
This commit is contained in:
@@ -110,11 +110,11 @@ export default {
|
||||
mounted() {
|
||||
this.handleResize();
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
this.$emitter.on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
bus.$off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
this.$emitter.off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ICON_REOPEN_CONVERSATION,
|
||||
ICON_RESOLVE_CONVERSATION,
|
||||
} from './CommandBarIcons';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
import { createSnoozeHandlers } from './commandBarActions';
|
||||
|
||||
@@ -37,7 +38,7 @@ export const RESOLVED_CONVERSATION_BULK_ACTIONS = [
|
||||
title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
|
||||
section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
|
||||
icon: ICON_REOPEN_CONVERSATION,
|
||||
handler: () => bus.$emit(CMD_BULK_ACTION_REOPEN_CONVERSATION),
|
||||
handler: () => emitter.emit(CMD_BULK_ACTION_REOPEN_CONVERSATION),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -47,7 +48,7 @@ export const OPEN_CONVERSATION_BULK_ACTIONS = [
|
||||
title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
|
||||
section: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
|
||||
icon: ICON_RESOLVE_CONVERSATION,
|
||||
handler: () => bus.$emit(CMD_BULK_ACTION_RESOLVE_CONVERSATION),
|
||||
handler: () => emitter.emit(CMD_BULK_ACTION_RESOLVE_CONVERSATION),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
import {
|
||||
CMD_MUTE_CONVERSATION,
|
||||
@@ -26,7 +27,7 @@ export const OPEN_CONVERSATION_ACTIONS = [
|
||||
title: 'COMMAND_BAR.COMMANDS.RESOLVE_CONVERSATION',
|
||||
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
|
||||
icon: ICON_RESOLVE_CONVERSATION,
|
||||
handler: () => bus.$emit(CMD_RESOLVE_CONVERSATION),
|
||||
handler: () => emitter.emit(CMD_RESOLVE_CONVERSATION),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -37,7 +38,7 @@ export const createSnoozeHandlers = (busEventName, parentId, section) => {
|
||||
parent: parentId,
|
||||
section: section,
|
||||
icon: ICON_SNOOZE_CONVERSATION,
|
||||
handler: () => bus.$emit(busEventName, option),
|
||||
handler: () => emitter.emit(busEventName, option),
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -61,7 +62,7 @@ export const RESOLVED_CONVERSATION_ACTIONS = [
|
||||
title: 'COMMAND_BAR.COMMANDS.REOPEN_CONVERSATION',
|
||||
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
|
||||
icon: ICON_REOPEN_CONVERSATION,
|
||||
handler: () => bus.$emit(CMD_REOPEN_CONVERSATION),
|
||||
handler: () => emitter.emit(CMD_REOPEN_CONVERSATION),
|
||||
},
|
||||
];
|
||||
|
||||
@@ -70,7 +71,7 @@ export const SEND_TRANSCRIPT_ACTION = {
|
||||
title: 'COMMAND_BAR.COMMANDS.SEND_TRANSCRIPT',
|
||||
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
|
||||
icon: ICON_SEND_TRANSCRIPT,
|
||||
handler: () => bus.$emit(CMD_SEND_TRANSCRIPT),
|
||||
handler: () => emitter.emit(CMD_SEND_TRANSCRIPT),
|
||||
};
|
||||
|
||||
export const UNMUTE_ACTION = {
|
||||
@@ -78,7 +79,7 @@ export const UNMUTE_ACTION = {
|
||||
title: 'COMMAND_BAR.COMMANDS.UNMUTE_CONVERSATION',
|
||||
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
|
||||
icon: ICON_UNMUTE_CONVERSATION,
|
||||
handler: () => bus.$emit(CMD_UNMUTE_CONVERSATION),
|
||||
handler: () => emitter.emit(CMD_UNMUTE_CONVERSATION),
|
||||
};
|
||||
|
||||
export const MUTE_ACTION = {
|
||||
@@ -86,5 +87,5 @@ export const MUTE_ACTION = {
|
||||
title: 'COMMAND_BAR.COMMANDS.MUTE_CONVERSATION',
|
||||
section: 'COMMAND_BAR.SECTIONS.CONVERSATION',
|
||||
icon: ICON_MUTE_CONVERSATION,
|
||||
handler: () => bus.$emit(CMD_MUTE_CONVERSATION),
|
||||
handler: () => emitter.emit(CMD_MUTE_CONVERSATION),
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
import { CMD_AI_ASSIST } from './commandBarBusEvents';
|
||||
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
|
||||
@@ -318,7 +319,7 @@ export default {
|
||||
section: this.$t('COMMAND_BAR.SECTIONS.AI_ASSIST'),
|
||||
priority: item,
|
||||
icon: item.icon,
|
||||
handler: () => bus.$emit(CMD_AI_ASSIST, item.key),
|
||||
handler: () => emitter.emit(CMD_AI_ASSIST, item.key),
|
||||
}));
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ import wootConstants from 'dashboard/constants/globals';
|
||||
|
||||
import { CMD_SNOOZE_NOTIFICATION } from './commandBarBusEvents';
|
||||
import { ICON_SNOOZE_NOTIFICATION } from './CommandBarIcons';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
import { isAInboxViewRoute } from 'dashboard/helper/routeHelpers';
|
||||
|
||||
@@ -21,7 +22,7 @@ const INBOX_SNOOZE_EVENTS = [
|
||||
section: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||
icon: ICON_SNOOZE_NOTIFICATION,
|
||||
handler: () =>
|
||||
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
|
||||
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.AN_HOUR_FROM_NOW),
|
||||
},
|
||||
{
|
||||
id: SNOOZE_OPTIONS.UNTIL_TOMORROW,
|
||||
@@ -30,7 +31,7 @@ const INBOX_SNOOZE_EVENTS = [
|
||||
parent: 'snooze_notification',
|
||||
icon: ICON_SNOOZE_NOTIFICATION,
|
||||
handler: () =>
|
||||
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_TOMORROW),
|
||||
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_TOMORROW),
|
||||
},
|
||||
{
|
||||
id: SNOOZE_OPTIONS.UNTIL_NEXT_WEEK,
|
||||
@@ -39,7 +40,7 @@ const INBOX_SNOOZE_EVENTS = [
|
||||
parent: 'snooze_notification',
|
||||
icon: ICON_SNOOZE_NOTIFICATION,
|
||||
handler: () =>
|
||||
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
|
||||
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_WEEK),
|
||||
},
|
||||
{
|
||||
id: SNOOZE_OPTIONS.UNTIL_NEXT_MONTH,
|
||||
@@ -48,7 +49,7 @@ const INBOX_SNOOZE_EVENTS = [
|
||||
parent: 'snooze_notification',
|
||||
icon: ICON_SNOOZE_NOTIFICATION,
|
||||
handler: () =>
|
||||
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
|
||||
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_NEXT_MONTH),
|
||||
},
|
||||
{
|
||||
id: SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME,
|
||||
@@ -57,7 +58,7 @@ const INBOX_SNOOZE_EVENTS = [
|
||||
parent: 'snooze_notification',
|
||||
icon: ICON_SNOOZE_NOTIFICATION,
|
||||
handler: () =>
|
||||
bus.$emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
|
||||
emitter.emit(CMD_SNOOZE_NOTIFICATION, SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME),
|
||||
},
|
||||
];
|
||||
export default {
|
||||
|
||||
@@ -7,13 +7,17 @@ export const routes = [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/contacts'),
|
||||
name: 'contacts_dashboard',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ContactsView,
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/contacts/custom_view/:id'),
|
||||
name: 'contacts_segments_dashboard',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ContactsView,
|
||||
props: route => {
|
||||
return { segmentsId: route.params.id };
|
||||
@@ -22,7 +26,9 @@ export const routes = [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/labels/:label/contacts'),
|
||||
name: 'contacts_labels_dashboard',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ContactsView,
|
||||
props: route => {
|
||||
return { label: route.params.label };
|
||||
@@ -31,7 +37,9 @@ export const routes = [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/contacts/:contactId'),
|
||||
name: 'contact_profile_dashboard',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ContactManageView,
|
||||
props: route => {
|
||||
return { contactId: route.params.contactId };
|
||||
|
||||
@@ -145,7 +145,6 @@ import CustomAttributes from './customAttributes/CustomAttributes.vue';
|
||||
import draggable from 'vuedraggable';
|
||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||
import MacrosList from './Macros/List.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AccordionItem,
|
||||
|
||||
@@ -19,12 +19,12 @@ const initiatedAt = computed(
|
||||
() => props.conversationAttributes.initiated_at?.timestamp
|
||||
);
|
||||
|
||||
const browserInfo = props.conversationAttributes.browser;
|
||||
const browserInfo = computed(() => props.conversationAttributes.browser);
|
||||
|
||||
const browserName = computed(() => {
|
||||
if (!browserInfo) return '';
|
||||
if (!browserInfo.value) return '';
|
||||
const { browser_name: name = '', browser_version: version = '' } =
|
||||
browserInfo;
|
||||
browserInfo.value;
|
||||
return `${name} ${version}`;
|
||||
});
|
||||
|
||||
@@ -33,9 +33,9 @@ const browserLanguage = computed(() =>
|
||||
);
|
||||
|
||||
const platformName = computed(() => {
|
||||
if (!browserInfo) return '';
|
||||
if (!browserInfo.value) return '';
|
||||
const { platform_name: name = '', platform_version: version = '' } =
|
||||
browserInfo;
|
||||
browserInfo.value;
|
||||
return `${name} ${version}`;
|
||||
});
|
||||
|
||||
|
||||
@@ -22,25 +22,40 @@
|
||||
:is-on-expanded-layout="isOnExpandedLayout"
|
||||
@contact-panel-toggle="onToggleContactPanel"
|
||||
/>
|
||||
<woot-modal
|
||||
:show.sync="showCustomSnoozeModal"
|
||||
:on-close="hideCustomSnoozeModal"
|
||||
>
|
||||
<custom-snooze-modal
|
||||
@close="hideCustomSnoozeModal"
|
||||
@choose-time="chooseSnoozeTime"
|
||||
/>
|
||||
</woot-modal>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { getUnixTime } from 'date-fns';
|
||||
import ChatList from '../../../components/ChatList.vue';
|
||||
import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue';
|
||||
import PopOverSearch from './search/PopOverSearch.vue';
|
||||
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal.vue';
|
||||
import uiSettingsMixin from 'dashboard/mixins/uiSettings';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import { CMD_SNOOZE_CONVERSATION } from 'dashboard/routes/dashboard/commands/commandBarBusEvents';
|
||||
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChatList,
|
||||
ConversationBox,
|
||||
PopOverSearch,
|
||||
CustomSnoozeModal,
|
||||
},
|
||||
mixins: [uiSettingsMixin],
|
||||
mixins: [uiSettingsMixin, alertMixin],
|
||||
props: {
|
||||
inboxId: {
|
||||
type: [String, Number],
|
||||
@@ -70,12 +85,14 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
showSearchModal: false,
|
||||
showCustomSnoozeModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
chatList: 'getAllConversations',
|
||||
currentChat: 'getSelectedChat',
|
||||
contextMenuChatId: 'getContextMenuChatId',
|
||||
}),
|
||||
showConversationList() {
|
||||
return this.isOnExpandedLayout ? !this.conversationId : true;
|
||||
@@ -112,6 +129,10 @@ export default {
|
||||
this.$watch('chatList.length', () => {
|
||||
this.setActiveChat();
|
||||
});
|
||||
this.$emitter.on(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$emitter.off(CMD_SNOOZE_CONVERSATION, this.onCmdSnoozeConversation);
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -169,7 +190,7 @@ export default {
|
||||
after: messageId,
|
||||
})
|
||||
.then(() => {
|
||||
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId });
|
||||
this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId });
|
||||
});
|
||||
} else {
|
||||
this.$store.dispatch('clearSelectedState');
|
||||
@@ -186,6 +207,43 @@ export default {
|
||||
closeSearch() {
|
||||
this.showSearchModal = false;
|
||||
},
|
||||
onCmdSnoozeConversation(snoozeType) {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
this.showCustomSnoozeModal = true;
|
||||
} else {
|
||||
this.toggleStatus(
|
||||
wootConstants.STATUS_TYPE.SNOOZED,
|
||||
findSnoozeTime(snoozeType) || null
|
||||
);
|
||||
}
|
||||
},
|
||||
chooseSnoozeTime(customSnoozeTime) {
|
||||
this.showCustomSnoozeModal = false;
|
||||
if (customSnoozeTime) {
|
||||
this.toggleStatus(
|
||||
wootConstants.STATUS_TYPE.SNOOZED,
|
||||
getUnixTime(customSnoozeTime)
|
||||
);
|
||||
}
|
||||
},
|
||||
toggleStatus(status, snoozedUntil) {
|
||||
this.$store
|
||||
.dispatch('toggleStatus', {
|
||||
conversationId: this.currentChat?.id || this.contextMenuChatId,
|
||||
status,
|
||||
snoozedUntil,
|
||||
})
|
||||
.then(() => {
|
||||
this.$store.dispatch('setContextMenuChatId', null);
|
||||
this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
|
||||
});
|
||||
},
|
||||
hideCustomSnoozeModal() {
|
||||
// if we select custom snooze and the custom snooze modal is open
|
||||
// Then if the custom snooze modal is closed then set the context menu chat id to null
|
||||
this.$store.dispatch('setContextMenuChatId', null);
|
||||
this.showCustomSnoozeModal = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -271,7 +271,10 @@ export default {
|
||||
},
|
||||
toggleConversationModal() {
|
||||
this.showConversationModal = !this.showConversationModal;
|
||||
bus.$emit(BUS_EVENTS.NEW_CONVERSATION_MODAL, this.showConversationModal);
|
||||
this.$emitter.emit(
|
||||
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
||||
this.showConversationModal
|
||||
);
|
||||
},
|
||||
toggleDeleteModal() {
|
||||
this.showDeleteModal = !this.showDeleteModal;
|
||||
|
||||
@@ -7,7 +7,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/dashboard'),
|
||||
name: 'home',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: () => {
|
||||
return { inboxId: 0 };
|
||||
@@ -16,7 +18,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/conversations/:conversation_id'),
|
||||
name: 'inbox_conversation',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => {
|
||||
return { inboxId: 0, conversationId: route.params.conversation_id };
|
||||
@@ -25,7 +29,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/inbox/:inbox_id'),
|
||||
name: 'inbox_dashboard',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => {
|
||||
return { inboxId: route.params.inbox_id };
|
||||
@@ -36,7 +42,9 @@ export default {
|
||||
'accounts/:accountId/inbox/:inbox_id/conversations/:conversation_id'
|
||||
),
|
||||
name: 'conversation_through_inbox',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => {
|
||||
return {
|
||||
@@ -48,7 +56,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/label/:label'),
|
||||
name: 'label_conversations',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({ label: route.params.label }),
|
||||
},
|
||||
@@ -57,7 +67,9 @@ export default {
|
||||
'accounts/:accountId/label/:label/conversations/:conversation_id'
|
||||
),
|
||||
name: 'conversations_through_label',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({
|
||||
conversationId: route.params.conversation_id,
|
||||
@@ -67,7 +79,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/team/:teamId'),
|
||||
name: 'team_conversations',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({ teamId: route.params.teamId }),
|
||||
},
|
||||
@@ -76,7 +90,9 @@ export default {
|
||||
'accounts/:accountId/team/:teamId/conversations/:conversationId'
|
||||
),
|
||||
name: 'conversations_through_team',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({
|
||||
conversationId: route.params.conversationId,
|
||||
@@ -86,7 +102,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/custom_view/:id'),
|
||||
name: 'folder_conversations',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({ foldersId: route.params.id }),
|
||||
},
|
||||
@@ -95,7 +113,9 @@ export default {
|
||||
'accounts/:accountId/custom_view/:id/conversations/:conversation_id'
|
||||
),
|
||||
name: 'conversations_through_folders',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({
|
||||
conversationId: route.params.conversation_id,
|
||||
@@ -105,7 +125,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/mentions/conversations'),
|
||||
name: 'conversation_mentions',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: () => ({ conversationType: 'mention' }),
|
||||
},
|
||||
@@ -114,7 +136,9 @@ export default {
|
||||
'accounts/:accountId/mentions/conversations/:conversationId'
|
||||
),
|
||||
name: 'conversation_through_mentions',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({
|
||||
conversationId: route.params.conversationId,
|
||||
@@ -124,7 +148,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/unattended/conversations'),
|
||||
name: 'conversation_unattended',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: () => ({ conversationType: 'unattended' }),
|
||||
},
|
||||
@@ -133,7 +159,9 @@ export default {
|
||||
'accounts/:accountId/unattended/conversations/:conversationId'
|
||||
),
|
||||
name: 'conversation_through_unattended',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({
|
||||
conversationId: route.params.conversationId,
|
||||
@@ -143,7 +171,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/participating/conversations'),
|
||||
name: 'conversation_participating',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: () => ({ conversationType: 'participating' }),
|
||||
},
|
||||
@@ -152,7 +182,9 @@ export default {
|
||||
'accounts/:accountId/participating/conversations/:conversationId'
|
||||
),
|
||||
name: 'conversation_through_participating',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ConversationView,
|
||||
props: route => ({
|
||||
conversationId: route.params.conversationId,
|
||||
|
||||
@@ -28,7 +28,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/suspended'),
|
||||
name: 'account_suspended',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: Suspended,
|
||||
},
|
||||
],
|
||||
|
||||
+2
-2
@@ -265,7 +265,7 @@ export default {
|
||||
},
|
||||
|
||||
mounted() {
|
||||
bus.$on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
this.$emitter.on(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
|
||||
const slug = this.$route.params.portalSlug;
|
||||
if (slug) this.lastActivePortalSlug = slug;
|
||||
@@ -273,7 +273,7 @@ export default {
|
||||
this.fetchPortalAndItsCategories();
|
||||
},
|
||||
beforeDestroy() {
|
||||
bus.$off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
this.$emitter.off(BUS_EVENTS.TOGGLE_SIDEMENU, this.toggleSidebar);
|
||||
},
|
||||
updated() {
|
||||
const slug = this.$route.params.portalSlug;
|
||||
|
||||
@@ -30,13 +30,17 @@ const portalRoutes = [
|
||||
{
|
||||
path: getPortalRoute(''),
|
||||
name: 'default_portal_articles',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: DefaultPortalArticles,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute('all'),
|
||||
name: 'list_all_portals',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllPortals,
|
||||
},
|
||||
{
|
||||
@@ -47,55 +51,73 @@ const portalRoutes = [
|
||||
path: '',
|
||||
name: 'new_portal_information',
|
||||
component: PortalDetails,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':portalSlug/customization',
|
||||
name: 'portal_customization',
|
||||
component: PortalCustomization,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':portalSlug/finish',
|
||||
name: 'portal_finish',
|
||||
component: PortalSettingsFinish,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug'),
|
||||
name: 'portalSlug',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ShowPortal,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/edit'),
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: EditPortal,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'edit_portal_information',
|
||||
component: EditPortalBasic,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'customizations',
|
||||
name: 'edit_portal_customization',
|
||||
component: EditPortalCustomization,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'locales',
|
||||
name: 'edit_portal_locales',
|
||||
component: EditPortalLocales,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'categories',
|
||||
name: 'list_all_locale_categories',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllCategories,
|
||||
},
|
||||
],
|
||||
@@ -106,39 +128,51 @@ const articleRoutes = [
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/articles'),
|
||||
name: 'list_all_locale_articles',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllArticles,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/articles/new'),
|
||||
name: 'new_article',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: NewArticle,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/articles/mine'),
|
||||
name: 'list_mine_articles',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllArticles,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/articles/archived'),
|
||||
name: 'list_archived_articles',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllArticles,
|
||||
},
|
||||
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/articles/draft'),
|
||||
name: 'list_draft_articles',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllArticles,
|
||||
},
|
||||
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/articles/:articleSlug'),
|
||||
name: 'edit_article',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: EditArticle,
|
||||
},
|
||||
];
|
||||
@@ -147,19 +181,25 @@ const categoryRoutes = [
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/categories'),
|
||||
name: 'all_locale_categories',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllCategories,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/categories/new'),
|
||||
name: 'new_category_in_locale',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: NewCategory,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/categories/:categorySlug'),
|
||||
name: 'show_category',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListAllArticles,
|
||||
},
|
||||
{
|
||||
@@ -167,13 +207,17 @@ const categoryRoutes = [
|
||||
':portalSlug/:locale/categories/:categorySlug/articles'
|
||||
),
|
||||
name: 'show_category_articles',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: ListCategoryArticles,
|
||||
},
|
||||
{
|
||||
path: getPortalRoute(':portalSlug/:locale/categories/:categorySlug'),
|
||||
name: 'edit_category',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: EditCategory,
|
||||
},
|
||||
];
|
||||
|
||||
+3
-3
@@ -35,7 +35,7 @@ const locales = computed(() => {
|
||||
});
|
||||
const allowedLocales = computed(() => {
|
||||
return Object.keys(locales.value).map(key => {
|
||||
return this.locales.value[key].code;
|
||||
return locales.value[key].code;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,7 +72,7 @@ async function updatePortalLocales({
|
||||
|
||||
function changeDefaultLocale({ localeCode }) {
|
||||
updatePortalLocales({
|
||||
allowedLocales: allowedLocales.value,
|
||||
newAllowedLocales: allowedLocales.value,
|
||||
defaultLocale: localeCode,
|
||||
messageKey: 'CHANGE_DEFAULT_LOCALE',
|
||||
});
|
||||
@@ -90,7 +90,7 @@ function deletePortalLocale({ localeCode }) {
|
||||
const defaultLocale = currentPortal.value?.meta.default_locale;
|
||||
|
||||
updatePortalLocales({
|
||||
allowedLocales: updatedLocales,
|
||||
newAllowedLocales: updatedLocales,
|
||||
defaultLocale,
|
||||
messageKey: 'DELETE_LOCALE',
|
||||
});
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
|
||||
import InboxCard from './components/InboxCard.vue';
|
||||
import InboxListHeader from './components/InboxListHeader.vue';
|
||||
import { INBOX_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
@@ -103,6 +104,13 @@ export default {
|
||||
return !this.uiFlags.isFetching && !this.notifications.length;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
inboxFilters(newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
this.$store.dispatch('notifications/updateNotificationFilters', newVal);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setSavedFilter();
|
||||
this.fetchNotifications();
|
||||
@@ -190,6 +198,10 @@ export default {
|
||||
this.status = status;
|
||||
this.type = type;
|
||||
this.sortOrder = sortBy || wootConstants.INBOX_SORT_BY.NEWEST;
|
||||
this.$store.dispatch(
|
||||
'notifications/setNotificationFilters',
|
||||
this.inboxFilters
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -140,7 +140,7 @@ export default {
|
||||
this.$store
|
||||
.dispatch('setActiveChat', { data: selectedConversation })
|
||||
.then(() => {
|
||||
bus.$emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
|
||||
this.$emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
|
||||
});
|
||||
},
|
||||
findConversation() {
|
||||
|
||||
@@ -92,10 +92,10 @@ export default {
|
||||
...mapGetters({ meta: 'notifications/getMeta' }),
|
||||
},
|
||||
mounted() {
|
||||
bus.$on(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||
this.$emitter.on(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||
},
|
||||
destroyed() {
|
||||
bus.$off(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||
this.$emitter.off(CMD_SNOOZE_NOTIFICATION, this.onCmdSnoozeNotification);
|
||||
},
|
||||
methods: {
|
||||
openSnoozeNotificationModal() {
|
||||
|
||||
@@ -12,13 +12,17 @@ export const routes = [
|
||||
path: '',
|
||||
name: 'inbox_view',
|
||||
component: InboxEmptyStateView,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':notification_id',
|
||||
name: 'inbox_view_conversation',
|
||||
component: InboxDetailView,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -18,7 +18,9 @@ export const routes = [
|
||||
path: '',
|
||||
name: 'notifications_index',
|
||||
component: NotificationsView,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -200,7 +200,7 @@ export default {
|
||||
},
|
||||
|
||||
featureInboundEmailEnabled() {
|
||||
return !!this.features.inbound_emails;
|
||||
return !!this.features?.inbound_emails;
|
||||
},
|
||||
|
||||
featureCustomReplyDomainEnabled() {
|
||||
|
||||
@@ -6,7 +6,9 @@ export default {
|
||||
routes: [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/settings/general'),
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'GENERAL_SETTINGS.TITLE',
|
||||
@@ -18,7 +20,9 @@ export default {
|
||||
path: '',
|
||||
name: 'general_settings_index',
|
||||
component: Index,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -8,7 +8,9 @@ export default {
|
||||
routes: [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/settings/agent-bots'),
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'AGENT_BOTS.HEADER',
|
||||
@@ -20,19 +22,25 @@ export default {
|
||||
path: '',
|
||||
name: 'agent_bots',
|
||||
component: Bot,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'csml/new',
|
||||
name: 'agent_bots_csml_new',
|
||||
component: CsmlNewBot,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'csml/:botId',
|
||||
name: 'agent_bots_csml_edit',
|
||||
component: CsmlEditBot,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -69,8 +69,10 @@
|
||||
<script>
|
||||
import { required, minLength, email } from 'vuelidate/lib/validators';
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
onClose: {
|
||||
type: Function,
|
||||
@@ -117,9 +119,6 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
showAlert(message) {
|
||||
bus.$emit('newToastMessage', message);
|
||||
},
|
||||
async addAgent() {
|
||||
try {
|
||||
await this.$store.dispatch('agents/create', {
|
||||
|
||||
@@ -83,6 +83,7 @@ import WootSubmitButton from '../../../../components/buttons/FormSubmitButton.vu
|
||||
import Modal from '../../../../components/Modal.vue';
|
||||
import Auth from '../../../../api/auth';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
const { AVAILABILITY_STATUS_KEYS } = wootConstants;
|
||||
|
||||
@@ -91,6 +92,7 @@ export default {
|
||||
WootSubmitButton,
|
||||
Modal,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
@@ -169,9 +171,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showAlert(message) {
|
||||
bus.$emit('newToastMessage', message);
|
||||
},
|
||||
async editAgent() {
|
||||
try {
|
||||
await this.$store.dispatch('agents/update', {
|
||||
|
||||
@@ -130,6 +130,7 @@ import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||
import Thumbnail from '../../../../components/widgets/Thumbnail.vue';
|
||||
import AddAgent from './AddAgent.vue';
|
||||
import EditAgent from './EditAgent.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -137,7 +138,7 @@ export default {
|
||||
EditAgent,
|
||||
Thumbnail,
|
||||
},
|
||||
mixins: [globalConfigMixin],
|
||||
mixins: [globalConfigMixin, alertMixin],
|
||||
data() {
|
||||
return {
|
||||
loading: {},
|
||||
@@ -230,19 +231,19 @@ export default {
|
||||
async deleteAgent(id) {
|
||||
try {
|
||||
await this.$store.dispatch('agents/delete', id);
|
||||
this.showAlert(this.$t('AGENT_MGMT.DELETE.API.SUCCESS_MESSAGE'));
|
||||
this.showAlertMessage(this.$t('AGENT_MGMT.DELETE.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('AGENT_MGMT.DELETE.API.ERROR_MESSAGE'));
|
||||
this.showAlertMessage(this.$t('AGENT_MGMT.DELETE.API.ERROR_MESSAGE'));
|
||||
}
|
||||
},
|
||||
// Show SnackBar
|
||||
showAlert(message) {
|
||||
showAlertMessage(message) {
|
||||
// Reset loading, current selected agent
|
||||
this.loading[this.currentAgent.id] = false;
|
||||
this.currentAgent = {};
|
||||
// Show message
|
||||
this.agentAPI.message = message;
|
||||
bus.$emit('newToastMessage', message);
|
||||
this.showAlert(message);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,14 +15,15 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'agents_wrapper',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'agent_list',
|
||||
component: AgentHome,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -15,14 +15,15 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'attributes_wrapper',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'attributes_list',
|
||||
component: AttributesHome,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -16,13 +16,14 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'auditlogs_wrapper',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'auditlogs_list',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: AuditLogsHome,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -15,14 +15,15 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'automation_wrapper',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'automation_list',
|
||||
component: Automation,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -6,7 +6,9 @@ export default {
|
||||
routes: [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/settings/billing'),
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: SettingsContent,
|
||||
props: {
|
||||
headerTitle: 'BILLING_SETTINGS.TITLE',
|
||||
@@ -18,7 +20,9 @@ export default {
|
||||
path: '',
|
||||
name: 'billing_settings_index',
|
||||
component: Index,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -19,7 +19,9 @@ export default {
|
||||
{
|
||||
path: 'ongoing',
|
||||
name: 'ongoing_campaigns',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: Index,
|
||||
},
|
||||
],
|
||||
@@ -35,7 +37,9 @@ export default {
|
||||
{
|
||||
path: 'one_off',
|
||||
name: 'one_off',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: Index,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -132,12 +132,14 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
import AddCanned from './AddCanned.vue';
|
||||
import EditCanned from './EditCanned.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddCanned,
|
||||
EditCanned,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
data() {
|
||||
return {
|
||||
loading: {},
|
||||
@@ -187,13 +189,13 @@ export default {
|
||||
});
|
||||
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
|
||||
},
|
||||
showAlert(message) {
|
||||
showAlertMessage(message) {
|
||||
// Reset loading, current selected agent
|
||||
this.loading[this.selectedResponse.id] = false;
|
||||
this.selectedResponse = {};
|
||||
// Show message
|
||||
this.cannedResponseAPI.message = message;
|
||||
bus.$emit('newToastMessage', message);
|
||||
this.showAlert(message);
|
||||
},
|
||||
// Edit Function
|
||||
openAddPopup() {
|
||||
@@ -230,12 +232,14 @@ export default {
|
||||
this.$store
|
||||
.dispatch('deleteCannedResponse', id)
|
||||
.then(() => {
|
||||
this.showAlert(this.$t('CANNED_MGMT.DELETE.API.SUCCESS_MESSAGE'));
|
||||
this.showAlertMessage(
|
||||
this.$t('CANNED_MGMT.DELETE.API.SUCCESS_MESSAGE')
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
const errorMessage =
|
||||
error?.message || this.$t('CANNED_MGMT.DELETE.API.ERROR_MESSAGE');
|
||||
this.showAlert(errorMessage);
|
||||
this.showAlertMessage(errorMessage);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -16,13 +16,14 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'canned_wrapper',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'canned_list',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: CannedHome,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -51,11 +51,13 @@ import { mapGetters } from 'vuex';
|
||||
import InboxMembersAPI from '../../../../api/inboxMembers';
|
||||
import router from '../../../index';
|
||||
import PageHeader from '../SettingsSubPageHeader.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageHeader,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
|
||||
validations: {
|
||||
selectedAgents: {
|
||||
@@ -98,7 +100,7 @@ export default {
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
bus.$emit('newToastMessage', error.message);
|
||||
this.showAlert(error.message);
|
||||
}
|
||||
this.isCreating = false;
|
||||
},
|
||||
|
||||
@@ -136,12 +136,13 @@ import Settings from './Settings.vue';
|
||||
import adminMixin from '../../../../mixins/isAdmin';
|
||||
import accountMixin from '../../../../mixins/account';
|
||||
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Settings,
|
||||
},
|
||||
mixins: [adminMixin, accountMixin, globalConfigMixin],
|
||||
mixins: [adminMixin, accountMixin, globalConfigMixin, alertMixin],
|
||||
data() {
|
||||
return {
|
||||
loading: {},
|
||||
@@ -194,15 +195,9 @@ export default {
|
||||
async deleteInbox({ id }) {
|
||||
try {
|
||||
await this.$store.dispatch('inboxes/delete', id);
|
||||
bus.$emit(
|
||||
'newToastMessage',
|
||||
this.$t('INBOX_MGMT.DELETE.API.SUCCESS_MESSAGE')
|
||||
);
|
||||
this.showAlert(this.$t('INBOX_MGMT.DELETE.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
bus.$emit(
|
||||
'newToastMessage',
|
||||
this.$t('INBOX_MGMT.DELETE.API.ERROR_MESSAGE')
|
||||
);
|
||||
this.showAlert(this.$t('INBOX_MGMT.DELETE.API.ERROR_MESSAGE'));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -21,10 +21,8 @@
|
||||
</woot-tabs>
|
||||
</setting-intro-banner>
|
||||
|
||||
<inbox-reconnection-required
|
||||
v-if="isReconnectionRequired"
|
||||
class="mx-8 mt-5"
|
||||
/>
|
||||
<microsoft-reauthorize v-if="microsoftUnauthorized" :inbox="inbox" />
|
||||
<facebook-reauthorize v-if="facebookUnauthorized" :inbox="inbox" />
|
||||
|
||||
<div v-if="selectedTabKey === 'inbox_settings'" class="mx-8">
|
||||
<settings-section
|
||||
@@ -402,7 +400,6 @@
|
||||
@click="updateInbox"
|
||||
/>
|
||||
</settings-section>
|
||||
<facebook-reauthorize v-if="isAFacebookInbox" :inbox-id="inbox.id" />
|
||||
</div>
|
||||
|
||||
<div v-if="selectedTabKey === 'collaborators'" class="mx-8">
|
||||
@@ -440,7 +437,7 @@ import WeeklyAvailability from './components/WeeklyAvailability.vue';
|
||||
import GreetingsEditor from 'shared/components/GreetingsEditor.vue';
|
||||
import ConfigurationPage from './settingsPage/ConfigurationPage.vue';
|
||||
import CollaboratorsPage from './settingsPage/CollaboratorsPage.vue';
|
||||
import InboxReconnectionRequired from './components/InboxReconnectionRequired';
|
||||
import MicrosoftReauthorize from './channels/microsoft/Reauthorize.vue';
|
||||
import WidgetBuilder from './WidgetBuilder.vue';
|
||||
import BotConfiguration from './components/BotConfiguration.vue';
|
||||
import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||
@@ -459,7 +456,7 @@ export default {
|
||||
WeeklyAvailability,
|
||||
WidgetBuilder,
|
||||
SenderNameExamplePreview,
|
||||
InboxReconnectionRequired,
|
||||
MicrosoftReauthorize,
|
||||
},
|
||||
mixins: [alertMixin, configMixin, inboxMixin],
|
||||
data() {
|
||||
@@ -544,7 +541,8 @@ export default {
|
||||
this.isALineChannel ||
|
||||
this.isAPIInbox ||
|
||||
(this.isAnEmailChannel && !this.inbox.provider) ||
|
||||
(this.isAnEmailChannel && this.inbox.provider === 'microsoft') ||
|
||||
this.isAMicrosoftInbox ||
|
||||
this.isAGoogleInbox ||
|
||||
this.isAWhatsAppChannel ||
|
||||
this.isAWebWidgetInbox
|
||||
) {
|
||||
@@ -621,8 +619,11 @@ export default {
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
isReconnectionRequired() {
|
||||
return false;
|
||||
microsoftUnauthorized() {
|
||||
return this.isAMicrosoftInbox && this.inbox.reauthorization_required;
|
||||
},
|
||||
facebookUnauthorized() {
|
||||
return this.isAFacebookInbox && this.inbox.reauthorization_required;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
:header-title="$t('INBOX_MGMT.ADD.EMAIL_PROVIDER.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.EMAIL_PROVIDER.DESCRIPTION')"
|
||||
/>
|
||||
<div class="grid grid-cols-4 max-w-3xl mx-0 mt-6">
|
||||
<div class="grid max-w-3xl grid-cols-4 mx-0 mt-6">
|
||||
<channel-selector
|
||||
v-for="emailProvider in emailProviderList"
|
||||
:key="emailProvider.key"
|
||||
@@ -20,58 +20,59 @@
|
||||
</div>
|
||||
</div>
|
||||
<microsoft v-else-if="provider === 'microsoft'" />
|
||||
<google v-else-if="provider === 'google'" />
|
||||
<forward-to-option v-else-if="provider === 'other_provider'" />
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import ForwardToOption from './emailChannels/ForwardToOption.vue';
|
||||
import Microsoft from './emailChannels/Microsoft.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import Google from './emailChannels/Google.vue';
|
||||
import ChannelSelector from 'dashboard/components/ChannelSelector.vue';
|
||||
import PageHeader from '../../SettingsSubPageHeader.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChannelSelector,
|
||||
ForwardToOption,
|
||||
Microsoft,
|
||||
PageHeader,
|
||||
},
|
||||
data() {
|
||||
return { provider: '' };
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
globalConfig: 'globalConfig/get',
|
||||
isAChatwootInstance: 'globalConfig/isAChatwootInstance',
|
||||
}),
|
||||
emailProviderList() {
|
||||
return [
|
||||
{
|
||||
title: this.$t('INBOX_MGMT.EMAIL_PROVIDERS.MICROSOFT'),
|
||||
isEnabled: !!this.globalConfig.azureAppId,
|
||||
key: 'microsoft',
|
||||
src: '/assets/images/dashboard/channels/microsoft.png',
|
||||
},
|
||||
{
|
||||
title: this.$t('INBOX_MGMT.EMAIL_PROVIDERS.OTHER_PROVIDERS'),
|
||||
isEnabled: true,
|
||||
key: 'other_provider',
|
||||
src: '/assets/images/dashboard/channels/email.png',
|
||||
},
|
||||
].filter(provider => {
|
||||
if (this.isAChatwootInstance) {
|
||||
return true;
|
||||
}
|
||||
return provider.isEnabled;
|
||||
});
|
||||
import { useStoreGetters } from 'dashboard/composables/store';
|
||||
import { useI18n } from 'dashboard/composables/useI18n';
|
||||
|
||||
const provider = ref('');
|
||||
|
||||
const getters = useStoreGetters();
|
||||
const { t } = useI18n();
|
||||
|
||||
const globalConfig = getters['globalConfig/get'];
|
||||
const isAChatwootInstance = getters['globalConfig/isAChatwootInstance'];
|
||||
|
||||
const emailProviderList = computed(() => {
|
||||
return [
|
||||
{
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.MICROSOFT'),
|
||||
isEnabled: !!globalConfig.value.azureAppId,
|
||||
key: 'microsoft',
|
||||
src: '/assets/images/dashboard/channels/microsoft.png',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClick(emailProvider) {
|
||||
if (emailProvider.isEnabled) {
|
||||
this.provider = emailProvider.key;
|
||||
}
|
||||
{
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.GOOGLE'),
|
||||
isEnabled: !!window.chatwootConfig.googleOAuthClientId,
|
||||
key: 'google',
|
||||
src: '/assets/images/dashboard/channels/google.png',
|
||||
},
|
||||
},
|
||||
};
|
||||
{
|
||||
title: t('INBOX_MGMT.EMAIL_PROVIDERS.OTHER_PROVIDERS'),
|
||||
isEnabled: true,
|
||||
key: 'other_provider',
|
||||
src: '/assets/images/dashboard/channels/email.png',
|
||||
},
|
||||
].filter(providerConfig => {
|
||||
if (isAChatwootInstance.value) {
|
||||
return true;
|
||||
}
|
||||
return providerConfig.isEnabled;
|
||||
});
|
||||
});
|
||||
|
||||
function onClick(emailProvider) {
|
||||
if (emailProvider.isEnabled) {
|
||||
this.provider = emailProvider.key;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<script setup>
|
||||
import OAuthChannel from './OAuthChannel.vue';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
defineComponent({
|
||||
name: 'GoogleOAuthChannel',
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<OAuthChannel
|
||||
provider="google"
|
||||
:title="$t('INBOX_MGMT.ADD.GOOGLE.TITLE')"
|
||||
:description="$t('INBOX_MGMT.ADD.GOOGLE.DESCRIPTION')"
|
||||
:input-placeholder="$t('INBOX_MGMT.ADD.GOOGLE.EMAIL_PLACEHOLDER')"
|
||||
:submit-button-text="$t('INBOX_MGMT.ADD.GOOGLE.SIGN_IN')"
|
||||
:error-message="$t('INBOX_MGMT.ADD.GOOGLE.ERROR_MESSAGE')"
|
||||
/>
|
||||
</template>
|
||||
+16
-68
@@ -1,71 +1,19 @@
|
||||
<template>
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<settings-sub-page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.MICROSOFT.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.MICROSOFT.DESCRIPTION')"
|
||||
/>
|
||||
<form
|
||||
class="microsoft--sign-in-form"
|
||||
@submit.prevent="requestAuthorization"
|
||||
>
|
||||
<woot-input
|
||||
v-model.trim="email"
|
||||
type="text"
|
||||
:placeholder="$t('INBOX_MGMT.ADD.MICROSOFT.EMAIL_PLACEHOLDER')"
|
||||
@blur="$v.email.$touch"
|
||||
/>
|
||||
<woot-submit-button
|
||||
icon="brand-twitter"
|
||||
button-text="Sign in with Microsoft"
|
||||
type="submit"
|
||||
:loading="isRequestingAuthorization"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import microsoftClient from 'dashboard/api/channel/microsoftClient';
|
||||
import SettingsSubPageHeader from '../../../SettingsSubPageHeader.vue';
|
||||
import { required, email } from 'vuelidate/lib/validators';
|
||||
<script setup>
|
||||
import OAuthChannel from './OAuthChannel.vue';
|
||||
import { defineComponent } from 'vue';
|
||||
|
||||
export default {
|
||||
components: { SettingsSubPageHeader },
|
||||
mixins: [alertMixin],
|
||||
data() {
|
||||
return { email: '', isRequestingAuthorization: false };
|
||||
},
|
||||
validations: {
|
||||
email: { required, email },
|
||||
},
|
||||
methods: {
|
||||
async requestAuthorization() {
|
||||
try {
|
||||
this.$v.$touch();
|
||||
if (this.$v.$invalid) return;
|
||||
|
||||
this.isRequestingAuthorization = true;
|
||||
const response = await microsoftClient.generateAuthorization({
|
||||
email: this.email,
|
||||
});
|
||||
const {
|
||||
data: { url },
|
||||
} = response;
|
||||
window.location.href = url;
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE'));
|
||||
} finally {
|
||||
this.isRequestingAuthorization = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
defineComponent({
|
||||
name: 'MicrosoftOAuthChannel',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.microsoft--sign-in-form {
|
||||
@apply mt-6;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<OAuthChannel
|
||||
provider="microsoft"
|
||||
:title="$t('INBOX_MGMT.ADD.MICROSOFT.TITLE')"
|
||||
:description="$t('INBOX_MGMT.ADD.MICROSOFT.DESCRIPTION')"
|
||||
:input-placeholder="$t('INBOX_MGMT.ADD.MICROSOFT.EMAIL_PLACEHOLDER')"
|
||||
:submit-button-text="$t('INBOX_MGMT.ADD.MICROSOFT.SIGN_IN')"
|
||||
:error-message="$t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import microsoftClient from 'dashboard/api/channel/microsoftClient';
|
||||
import googleClient from 'dashboard/api/channel/googleClient';
|
||||
import SettingsSubPageHeader from '../../../SettingsSubPageHeader.vue';
|
||||
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
|
||||
const props = defineProps({
|
||||
provider: {
|
||||
type: String,
|
||||
required: true,
|
||||
validate: value => ['microsoft', 'google'].includes(value),
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
submitButtonText: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
errorMessage: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
inputPlaceholder: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const isRequestingAuthorization = ref(false);
|
||||
const email = ref('');
|
||||
|
||||
const client = computed(() => {
|
||||
if (props.provider === 'microsoft') {
|
||||
return microsoftClient;
|
||||
}
|
||||
|
||||
return googleClient;
|
||||
});
|
||||
|
||||
async function requestAuthorization() {
|
||||
try {
|
||||
isRequestingAuthorization.value = true;
|
||||
const response = await client.value.generateAuthorization({
|
||||
email: email.value,
|
||||
});
|
||||
const {
|
||||
data: { url },
|
||||
} = response;
|
||||
|
||||
window.location.href = url;
|
||||
} catch (error) {
|
||||
useAlert(props.errorMessage);
|
||||
} finally {
|
||||
isRequestingAuthorization.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6 w-full max-w-full md:w-3/4 md:max-w-[75%] flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
<settings-sub-page-header
|
||||
:header-title="title"
|
||||
:header-content="description"
|
||||
/>
|
||||
<form class="mt-6" @submit.prevent="requestAuthorization">
|
||||
<woot-input
|
||||
v-model="email"
|
||||
type="email"
|
||||
:placeholder="inputPlaceholder"
|
||||
/>
|
||||
<woot-submit-button
|
||||
icon="brand-twitter"
|
||||
type="submit"
|
||||
:button-text="submitButtonText"
|
||||
:loading="isRequestingAuthorization"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
+41
-60
@@ -1,63 +1,44 @@
|
||||
<template>
|
||||
<div class="mx-8">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.MICROSOFT.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.MICROSOFT.SUBTITLE')"
|
||||
>
|
||||
<div class="mb-6">
|
||||
<form @submit.prevent="requestAuthorization">
|
||||
<woot-submit-button
|
||||
icon="brand-twitter"
|
||||
button-text="Sign in with Microsoft"
|
||||
type="submit"
|
||||
:loading="isRequestingAuthorization"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</settings-section>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import microsoftClient from '../../../../../../api/channel/microsoftClient';
|
||||
import SettingsSection from '../../../../../../components/SettingsSection.vue';
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import InboxReconnectionRequired from '../../components/InboxReconnectionRequired';
|
||||
import microsoftClient from 'dashboard/api/channel/microsoftClient';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsSection,
|
||||
import { useI18n } from 'dashboard/composables/useI18n';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
inbox: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
inbox: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return { isRequestingAuthorization: false };
|
||||
},
|
||||
methods: {
|
||||
async requestAuthorization() {
|
||||
try {
|
||||
this.isRequestingAuthorization = true;
|
||||
const response = await microsoftClient.generateAuthorization({
|
||||
email: this.inbox.email,
|
||||
});
|
||||
const {
|
||||
data: { url },
|
||||
} = response;
|
||||
window.location.href = url;
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE'));
|
||||
} finally {
|
||||
this.isRequestingAuthorization = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.smtp-details-wrap {
|
||||
margin-bottom: var(--space-medium);
|
||||
});
|
||||
|
||||
const isRequestingAuthorization = ref(false);
|
||||
|
||||
async function requestAuthorization() {
|
||||
try {
|
||||
isRequestingAuthorization.value = true;
|
||||
const response = await microsoftClient.generateAuthorization({
|
||||
email: props.inbox.email,
|
||||
});
|
||||
|
||||
const {
|
||||
data: { url },
|
||||
} = response;
|
||||
window.location.href = url;
|
||||
} catch (error) {
|
||||
useAlert(t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE'));
|
||||
} finally {
|
||||
isRequestingAuthorization.value = false;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<inbox-reconnection-required
|
||||
class="mx-8 mt-5"
|
||||
@reauthorize="requestAuthorization"
|
||||
/>
|
||||
</template>
|
||||
|
||||
+9
-14
@@ -1,19 +1,14 @@
|
||||
<script setup>
|
||||
defineProps({
|
||||
actionUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex items-center gap-2 px-4 py-3 text-sm text-white bg-red-500 rounded-md dark:bg-red-800/30 dark:text-red-50 min-h-10"
|
||||
>
|
||||
<fluent-icon icon="error-circle" class="text-white dark:text-red-50" />
|
||||
<slot>
|
||||
<span v-html="$t('INBOX_MGMT.RECONNECTION_REQUIRED', { actionUrl })" />
|
||||
</slot>
|
||||
</div>
|
||||
<banner
|
||||
color-scheme="alert"
|
||||
class="justify-start rounded-md"
|
||||
:banner-message="$t('INBOX_MGMT.RECONNECTION_REQUIRED')"
|
||||
:action-button-label="$t('INBOX_MGMT.CLICK_TO_RECONNECT')"
|
||||
has-action-button
|
||||
@click="$emit('reauthorize')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,38 +1,32 @@
|
||||
<template>
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.FACEBOOK_REAUTHORIZE.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.FACEBOOK_REAUTHORIZE.SUBTITLE')"
|
||||
>
|
||||
<a class="fb--login" href="#" @click="tryFBlogin">
|
||||
<img
|
||||
src="~dashboard/assets/images/channels/facebook_login.png"
|
||||
alt="Facebook-logo"
|
||||
/>
|
||||
</a>
|
||||
</settings-section>
|
||||
<inbox-reconnection-required class="mx-8 mt-5" @reauthorize="tryFBlogin" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* global FB */
|
||||
import SettingsSection from '../../../../../components/SettingsSection.vue';
|
||||
import InboxReconnectionRequired from '../components/InboxReconnectionRequired';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsSection,
|
||||
InboxReconnectionRequired,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
inboxId: {
|
||||
type: Number,
|
||||
inbox: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
inboxId() {
|
||||
return this.inbox.id;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initFB();
|
||||
this.loadFBsdk();
|
||||
},
|
||||
|
||||
methods: {
|
||||
initFB() {
|
||||
if (window.fbSDKLoaded === undefined) {
|
||||
|
||||
@@ -28,14 +28,15 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'settings_inbox',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'settings_inbox_list',
|
||||
component: InboxHome,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
@@ -45,19 +46,25 @@ export default {
|
||||
path: '',
|
||||
name: 'settings_inbox_new',
|
||||
component: ChannelList,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':inbox_id/finish',
|
||||
name: 'settings_inbox_finish',
|
||||
component: FinishSetup,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':sub_page',
|
||||
name: 'settings_inboxes_page_channel',
|
||||
component: channelFactory.create(),
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
props: route => {
|
||||
return { channel_name: route.params.sub_page };
|
||||
},
|
||||
@@ -65,7 +72,9 @@ export default {
|
||||
{
|
||||
path: ':inbox_id/agents',
|
||||
name: 'settings_inboxes_add_agents',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: AddAgents,
|
||||
},
|
||||
],
|
||||
@@ -74,7 +83,9 @@ export default {
|
||||
path: ':inboxId',
|
||||
name: 'settings_inbox_show',
|
||||
component: Settings,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
+1
-7
@@ -104,10 +104,6 @@
|
||||
</div>
|
||||
<imap-settings :inbox="inbox" />
|
||||
<smtp-settings v-if="inbox.imap_enabled" :inbox="inbox" />
|
||||
<microsoft-reauthorize
|
||||
v-if="inbox.microsoft_reauthorization"
|
||||
:inbox="inbox"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="isAWhatsAppChannel && !isATwilioChannel">
|
||||
<div v-if="inbox.provider_config" class="mx-8">
|
||||
@@ -130,7 +126,7 @@
|
||||
"
|
||||
>
|
||||
<div
|
||||
class="whatsapp-settings--content items-center flex flex-1 justify-between mt-2"
|
||||
class="flex items-center justify-between flex-1 mt-2 whatsapp-settings--content"
|
||||
>
|
||||
<woot-input
|
||||
v-model.trim="whatsAppInboxAPIKey"
|
||||
@@ -160,7 +156,6 @@ import inboxMixin from 'shared/mixins/inboxMixin';
|
||||
import SettingsSection from '../../../../../components/SettingsSection.vue';
|
||||
import ImapSettings from '../ImapSettings.vue';
|
||||
import SmtpSettings from '../SmtpSettings.vue';
|
||||
import MicrosoftReauthorize from '../channels/microsoft/Reauthorize.vue';
|
||||
import { required } from 'vuelidate/lib/validators';
|
||||
|
||||
export default {
|
||||
@@ -168,7 +163,6 @@ export default {
|
||||
SettingsSection,
|
||||
ImapSettings,
|
||||
SmtpSettings,
|
||||
MicrosoftReauthorize,
|
||||
},
|
||||
mixins: [inboxMixin, alertMixin],
|
||||
props: {
|
||||
|
||||
+6
-2
@@ -26,13 +26,17 @@ export default {
|
||||
path: '',
|
||||
name: 'settings_applications',
|
||||
component: Index,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':integration_id',
|
||||
name: 'settings_applications_integration',
|
||||
component: IntegrationHooks,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
props: route => ({
|
||||
integrationId: route.params.integration_id,
|
||||
}),
|
||||
|
||||
+15
-5
@@ -30,32 +30,42 @@ export default {
|
||||
path: '',
|
||||
name: 'settings_integrations',
|
||||
component: Index,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'webhook',
|
||||
component: Webhook,
|
||||
name: 'settings_integrations_webhook',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'dashboard-apps',
|
||||
component: DashboardApps,
|
||||
name: 'settings_integrations_dashboard_apps',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'slack',
|
||||
name: 'settings_integrations_slack',
|
||||
component: Slack,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
props: route => ({ code: route.query.code }),
|
||||
},
|
||||
{
|
||||
path: ':integration_id',
|
||||
name: 'settings_integrations_integration',
|
||||
component: ShowIntegration,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
props: route => {
|
||||
return {
|
||||
integrationId: route.params.integration_id,
|
||||
|
||||
@@ -17,13 +17,17 @@ export default {
|
||||
{
|
||||
path: '',
|
||||
name: 'labels_wrapper',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'labels_list',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: Index,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -23,19 +23,25 @@ export default {
|
||||
path: '',
|
||||
name: 'macros_wrapper',
|
||||
component: Macros,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
name: 'macros_new',
|
||||
component: MacroEditor,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':macroId/edit',
|
||||
name: 'macros_edit',
|
||||
component: MacroEditor,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -8,14 +8,18 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/profile'),
|
||||
name: 'profile_settings',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
component: SettingsContent,
|
||||
children: [
|
||||
{
|
||||
path: 'settings',
|
||||
name: 'profile_settings_index',
|
||||
component: Index,
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -144,7 +144,7 @@ export default {
|
||||
this.$store.dispatch('teams/get');
|
||||
this.fetchAllData();
|
||||
|
||||
bus.$on('fetch_overview_reports', () => {
|
||||
this.$emitter.on('fetch_overview_reports', () => {
|
||||
this.fetchAllData();
|
||||
});
|
||||
},
|
||||
|
||||
+3
@@ -125,6 +125,9 @@ export default {
|
||||
{}
|
||||
);
|
||||
},
|
||||
onPageNumberChange(pageIndex) {
|
||||
this.$emit('page-change', pageIndex);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -29,7 +29,9 @@ export default {
|
||||
{
|
||||
path: 'overview',
|
||||
name: 'account_overview_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: LiveReports,
|
||||
},
|
||||
],
|
||||
@@ -46,7 +48,9 @@ export default {
|
||||
{
|
||||
path: 'conversation',
|
||||
name: 'conversation_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: Index,
|
||||
},
|
||||
],
|
||||
@@ -63,7 +67,9 @@ export default {
|
||||
{
|
||||
path: 'csat',
|
||||
name: 'csat_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: CsatResponses,
|
||||
},
|
||||
],
|
||||
@@ -80,7 +86,9 @@ export default {
|
||||
{
|
||||
path: 'bot',
|
||||
name: 'bot_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: BotReports,
|
||||
},
|
||||
],
|
||||
@@ -97,7 +105,9 @@ export default {
|
||||
{
|
||||
path: 'agent',
|
||||
name: 'agent_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: AgentReports,
|
||||
},
|
||||
],
|
||||
@@ -114,7 +124,9 @@ export default {
|
||||
{
|
||||
path: 'label',
|
||||
name: 'label_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: LabelReports,
|
||||
},
|
||||
],
|
||||
@@ -131,7 +143,9 @@ export default {
|
||||
{
|
||||
path: 'inboxes',
|
||||
name: 'inbox_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: InboxReports,
|
||||
},
|
||||
],
|
||||
@@ -147,7 +161,9 @@ export default {
|
||||
{
|
||||
path: 'teams',
|
||||
name: 'team_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: TeamReports,
|
||||
},
|
||||
],
|
||||
@@ -164,7 +180,9 @@ export default {
|
||||
{
|
||||
path: 'sla',
|
||||
name: 'sla_reports',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: SLAReports,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -24,7 +24,9 @@ export default {
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/settings'),
|
||||
name: 'settings_home',
|
||||
roles: ['administrator', 'agent'],
|
||||
meta: {
|
||||
permissions: ['administrator', 'agent'],
|
||||
},
|
||||
redirect: () => {
|
||||
if (store.getters.getCurrentRole === 'administrator') {
|
||||
return frontendURL('accounts/:accountId/settings/general');
|
||||
|
||||
@@ -13,13 +13,17 @@ export default {
|
||||
{
|
||||
path: '',
|
||||
name: 'sla_wrapper',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'sla_list',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: Index,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -29,14 +29,15 @@ export default {
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'settings_teams',
|
||||
redirect: 'list',
|
||||
},
|
||||
{
|
||||
path: 'list',
|
||||
name: 'settings_teams_list',
|
||||
component: TeamsHome,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'new',
|
||||
@@ -46,18 +47,24 @@ export default {
|
||||
path: '',
|
||||
name: 'settings_teams_new',
|
||||
component: CreateTeam,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':teamId/finish',
|
||||
name: 'settings_teams_finish',
|
||||
component: FinishSetup,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: ':teamId/agents',
|
||||
name: 'settings_teams_add_agents',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: AddAgents,
|
||||
},
|
||||
],
|
||||
@@ -70,18 +77,24 @@ export default {
|
||||
path: '',
|
||||
name: 'settings_teams_edit',
|
||||
component: EditTeam,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'agents',
|
||||
name: 'settings_teams_edit_members',
|
||||
component: EditAgents,
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'finish',
|
||||
name: 'settings_teams_edit_finish',
|
||||
roles: ['administrator'],
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
component: FinishSetup,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
<script setup>
|
||||
import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const toggleSupportWidgetVisibility = () => {
|
||||
if (window.$chatwoot) {
|
||||
window.$chatwoot.toggleBubbleVisibility('show');
|
||||
}
|
||||
};
|
||||
|
||||
const setupListenerForWidgetEvent = () => {
|
||||
window.addEventListener('chatwoot:on-message', () => {
|
||||
toggleSupportWidgetVisibility();
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
toggleSupportWidgetVisibility();
|
||||
setupListenerForWidgetEvent();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="suspended-page">
|
||||
<div class="items-center bg-slate-50 flex justify-center h-full w-full">
|
||||
<empty-state
|
||||
:title="$t('APP_GLOBAL.ACCOUNT_SUSPENDED.TITLE')"
|
||||
:message="$t('APP_GLOBAL.ACCOUNT_SUSPENDED.MESSAGE')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
|
||||
export default {
|
||||
components: { EmptyState },
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.suspended-page {
|
||||
align-items: center;
|
||||
background: var(--s-50);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,33 +5,12 @@ import dashboard from './dashboard/dashboard.routes';
|
||||
import store from '../store';
|
||||
import { validateLoggedInRoutes } from '../helper/routeHelpers';
|
||||
import AnalyticsHelper from '../helper/AnalyticsHelper';
|
||||
import { buildPermissionsFromRouter } from '../helper/permissionsHelper';
|
||||
|
||||
const routes = [...dashboard.routes];
|
||||
|
||||
window.roleWiseRoutes = {
|
||||
agent: [],
|
||||
administrator: [],
|
||||
};
|
||||
|
||||
// generateRoleWiseRoute - updates window object with agent/admin route
|
||||
const generateRoleWiseRoute = route => {
|
||||
route.forEach(element => {
|
||||
if (element.children) {
|
||||
generateRoleWiseRoute(element.children);
|
||||
}
|
||||
if (element.roles) {
|
||||
element.roles.forEach(roleEl => {
|
||||
window.roleWiseRoutes[roleEl].push(element.name);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
// Create a object of routes
|
||||
// accessible by each role.
|
||||
// returns an object with roles as keys and routeArr as values
|
||||
generateRoleWiseRoute(routes);
|
||||
|
||||
export const router = new VueRouter({ mode: 'history', routes });
|
||||
export const routesWithPermissions = buildPermissionsFromRouter(routes);
|
||||
|
||||
export const validateAuthenticateRoutePermission = (to, next, { getters }) => {
|
||||
const { isLoggedIn, getCurrentUser: user } = getters;
|
||||
@@ -45,11 +24,7 @@ export const validateAuthenticateRoutePermission = (to, next, { getters }) => {
|
||||
return next(frontendURL(`accounts/${user.account_id}/dashboard`));
|
||||
}
|
||||
|
||||
const nextRoute = validateLoggedInRoutes(
|
||||
to,
|
||||
getters.getCurrentUser,
|
||||
window.roleWiseRoutes
|
||||
);
|
||||
const nextRoute = validateLoggedInRoutes(to, getters.getCurrentUser);
|
||||
return nextRoute ? next(frontendURL(nextRoute)) : next();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user