fix: merge develop and address PR review comments
This commit is contained in:
@@ -191,7 +191,7 @@ onMounted(() => {
|
||||
|
||||
<template>
|
||||
<PageLayout
|
||||
:header-title="$t('CAPTAIN.DOCUMENTS.HEADER')"
|
||||
:header-title="$t('CAPTAIN.ASSISTANTS.SCENARIOS.TITLE')"
|
||||
:is-fetching="isFetching"
|
||||
:show-know-more="false"
|
||||
:show-pagination-footer="false"
|
||||
|
||||
@@ -31,6 +31,8 @@ const toggleStatus = async (status, snoozedUntil) => {
|
||||
const onCmdSnoozeConversation = snoozeType => {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
showCustomSnoozeModal.value = true;
|
||||
} else if (typeof snoozeType === 'number') {
|
||||
toggleStatus(wootConstants.STATUS_TYPE.SNOOZED, snoozeType);
|
||||
} else {
|
||||
toggleStatus(
|
||||
wootConstants.STATUS_TYPE.SNOOZED,
|
||||
|
||||
@@ -4,16 +4,29 @@ import { ref, computed, watchEffect, onMounted } from 'vue';
|
||||
import { useStore } from 'dashboard/composables/store';
|
||||
import { useTrack } from 'dashboard/composables';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useLocale } from 'shared/composables/useLocale';
|
||||
import { useAppearanceHotKeys } from 'dashboard/composables/commands/useAppearanceHotKeys';
|
||||
import { useInboxHotKeys } from 'dashboard/composables/commands/useInboxHotKeys';
|
||||
import { useGoToCommandHotKeys } from 'dashboard/composables/commands/useGoToCommandHotKeys';
|
||||
import { useBulkActionsHotKeys } from 'dashboard/composables/commands/useBulkActionsHotKeys';
|
||||
import { useConversationHotKeys } from 'dashboard/composables/commands/useConversationHotKeys';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { GENERAL_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import {
|
||||
GENERAL_EVENTS,
|
||||
SNOOZE_EVENTS,
|
||||
} from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import { generateSnoozeSuggestions } from 'dashboard/helper/snoozeHelpers';
|
||||
import { ICON_SNOOZE_CONVERSATION } from 'dashboard/helper/commandbar/icons';
|
||||
import {
|
||||
CMD_SNOOZE_CONVERSATION,
|
||||
CMD_SNOOZE_NOTIFICATION,
|
||||
CMD_BULK_ACTION_SNOOZE_CONVERSATION,
|
||||
} from 'dashboard/helper/commandbar/events';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
const store = useStore();
|
||||
const { t } = useI18n();
|
||||
const { t, tm } = useI18n();
|
||||
const { resolvedLocale } = useLocale();
|
||||
|
||||
const ninjakeys = ref(null);
|
||||
|
||||
@@ -28,48 +41,168 @@ const { goToCommandHotKeys } = useGoToCommandHotKeys();
|
||||
const { bulkActionsHotKeys } = useBulkActionsHotKeys();
|
||||
const { conversationHotKeys } = useConversationHotKeys();
|
||||
|
||||
const placeholder = computed(() => t('COMMAND_BAR.SEARCH_PLACEHOLDER'));
|
||||
const SNOOZE_PARENT_IDS = [
|
||||
'snooze_conversation',
|
||||
'snooze_notification',
|
||||
'bulk_action_snooze_conversation',
|
||||
];
|
||||
const DYNAMIC_SNOOZE_PREFIX = 'dynamic_snooze_';
|
||||
|
||||
const hotKeys = computed(() => [
|
||||
...inboxHotKeys.value,
|
||||
...goToCommandHotKeys.value,
|
||||
...goToAppearanceHotKeys.value,
|
||||
...bulkActionsHotKeys.value,
|
||||
...conversationHotKeys.value,
|
||||
]);
|
||||
const CUSTOM_SNOOZE = wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME;
|
||||
|
||||
const dynamicSnoozeActions = ref([]);
|
||||
const currentCommandRoot = ref(null);
|
||||
|
||||
const placeholder = computed(() =>
|
||||
SNOOZE_PARENT_IDS.includes(currentCommandRoot.value)
|
||||
? t('COMMAND_BAR.SNOOZE_PLACEHOLDER')
|
||||
: t('COMMAND_BAR.SEARCH_PLACEHOLDER')
|
||||
);
|
||||
|
||||
const SNOOZE_PRESET_IDS = new Set(Object.values(wootConstants.SNOOZE_OPTIONS));
|
||||
|
||||
const hotKeys = computed(() => {
|
||||
const allActions = [
|
||||
...dynamicSnoozeActions.value,
|
||||
...inboxHotKeys.value,
|
||||
...goToCommandHotKeys.value,
|
||||
...goToAppearanceHotKeys.value,
|
||||
...bulkActionsHotKeys.value,
|
||||
...conversationHotKeys.value,
|
||||
];
|
||||
// When dynamic NLP snooze suggestions exist, hide all preset snooze actions to avoid duplication
|
||||
if (!dynamicSnoozeActions.value.length) return allActions;
|
||||
return allActions.filter(
|
||||
a => !SNOOZE_PRESET_IDS.has(a.id) || !SNOOZE_PARENT_IDS.includes(a.parent)
|
||||
);
|
||||
});
|
||||
|
||||
const setCommandBarData = () => {
|
||||
ninjakeys.value.data = hotKeys.value;
|
||||
};
|
||||
|
||||
const onSelected = item => {
|
||||
const {
|
||||
detail: { action: { title = null, section = null, id = null } = {} } = {},
|
||||
} = item;
|
||||
// Added this condition to prevent setting the selectedSnoozeType to null
|
||||
// When we select the "custom snooze" (CMD bar will close and the custom snooze modal will open)
|
||||
if (id === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
selectedSnoozeType.value = wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME;
|
||||
} else {
|
||||
selectedSnoozeType.value = null;
|
||||
const SNOOZE_EVENT_MAP = {
|
||||
snooze_conversation: CMD_SNOOZE_CONVERSATION,
|
||||
snooze_notification: CMD_SNOOZE_NOTIFICATION,
|
||||
bulk_action_snooze_conversation: CMD_BULK_ACTION_SNOOZE_CONVERSATION,
|
||||
};
|
||||
|
||||
const SNOOZE_SECTION_MAP = {
|
||||
snooze_conversation: 'COMMAND_BAR.SECTIONS.SNOOZE_CONVERSATION',
|
||||
snooze_notification: 'COMMAND_BAR.SECTIONS.SNOOZE_NOTIFICATION',
|
||||
bulk_action_snooze_conversation: 'COMMAND_BAR.SECTIONS.BULK_ACTIONS',
|
||||
};
|
||||
|
||||
const snoozeTranslations = computed(() => {
|
||||
const raw = tm('SNOOZE_PARSER');
|
||||
if (!raw || typeof raw !== 'object') return {};
|
||||
return JSON.parse(JSON.stringify(raw));
|
||||
});
|
||||
|
||||
const buildDynamicSnoozeActions = (search, parentId) => {
|
||||
const suggestions = generateSnoozeSuggestions(search, new Date(), {
|
||||
translations: snoozeTranslations.value,
|
||||
locale: resolvedLocale.value,
|
||||
});
|
||||
if (!suggestions.length) return [];
|
||||
|
||||
const busEvent = SNOOZE_EVENT_MAP[parentId];
|
||||
const section = t(SNOOZE_SECTION_MAP[parentId]);
|
||||
|
||||
return suggestions.map((parsed, index) => ({
|
||||
id: `${DYNAMIC_SNOOZE_PREFIX}${index}`,
|
||||
title:
|
||||
parsed.label !== parsed.formattedDate
|
||||
? `${parsed.label} - ${parsed.formattedDate}`
|
||||
: parsed.formattedDate,
|
||||
parent: parentId,
|
||||
section,
|
||||
icon: ICON_SNOOZE_CONVERSATION,
|
||||
keywords: search,
|
||||
handler: () => {
|
||||
emitter.emit(busEvent, parsed.resolve());
|
||||
useTrack(SNOOZE_EVENTS.NLP_SNOOZE_APPLIED, { label: parsed.label });
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const resetSnoozeState = () => {
|
||||
currentCommandRoot.value = null;
|
||||
dynamicSnoozeActions.value = [];
|
||||
};
|
||||
|
||||
const patchNinjaKeysOpenClose = el => {
|
||||
if (!el || typeof el.open !== 'function' || typeof el.close !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
useTrack(GENERAL_EVENTS.COMMAND_BAR, {
|
||||
section,
|
||||
action: title,
|
||||
});
|
||||
const originalOpen = el.open.bind(el);
|
||||
const originalClose = el.close.bind(el);
|
||||
|
||||
el.open = (...args) => {
|
||||
const [options = {}] = args;
|
||||
currentCommandRoot.value = options.parent || null;
|
||||
dynamicSnoozeActions.value = [];
|
||||
return originalOpen(...args);
|
||||
};
|
||||
|
||||
el.close = (...args) => {
|
||||
resetSnoozeState();
|
||||
return originalClose(...args);
|
||||
};
|
||||
};
|
||||
|
||||
const onSelected = item => {
|
||||
const {
|
||||
detail: {
|
||||
action: { title = null, section = null, id = null, children = null } = {},
|
||||
} = {},
|
||||
} = item;
|
||||
|
||||
selectedSnoozeType.value = id === CUSTOM_SNOOZE ? id : null;
|
||||
|
||||
if (Array.isArray(children) && children.length) {
|
||||
currentCommandRoot.value = id;
|
||||
}
|
||||
|
||||
useTrack(GENERAL_EVENTS.COMMAND_BAR, { section, action: title });
|
||||
setCommandBarData();
|
||||
};
|
||||
|
||||
const onClosed = () => {
|
||||
// If the selectedSnoozeType is not "SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME (custom snooze)" then we set the context menu chat id to null
|
||||
// Else we do nothing and its handled in the ChatList.vue hideCustomSnoozeModal() method
|
||||
const onCommandBarChange = item => {
|
||||
const { detail: { search = '', actions = [] } = {} } = item;
|
||||
const normalizedSearch = search.trim();
|
||||
|
||||
if (actions.length > 0) {
|
||||
const uniqueParents = [
|
||||
...new Set(actions.map(action => action.parent).filter(Boolean)),
|
||||
];
|
||||
if (uniqueParents.length === 1) {
|
||||
currentCommandRoot.value = uniqueParents[0];
|
||||
} else {
|
||||
currentCommandRoot.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
selectedSnoozeType.value !== wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME
|
||||
!normalizedSearch ||
|
||||
!SNOOZE_PARENT_IDS.includes(currentCommandRoot.value || '')
|
||||
) {
|
||||
dynamicSnoozeActions.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
dynamicSnoozeActions.value = buildDynamicSnoozeActions(
|
||||
normalizedSearch,
|
||||
currentCommandRoot.value
|
||||
);
|
||||
};
|
||||
|
||||
const onClosed = () => {
|
||||
if (selectedSnoozeType.value !== CUSTOM_SNOOZE) {
|
||||
store.dispatch('setContextMenuChatId', null);
|
||||
}
|
||||
resetSnoozeState();
|
||||
};
|
||||
|
||||
watchEffect(() => {
|
||||
@@ -78,7 +211,10 @@ watchEffect(() => {
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(setCommandBarData);
|
||||
onMounted(() => {
|
||||
setCommandBarData();
|
||||
patchNinjaKeysOpenClose(ninjakeys.value);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- eslint-disable vue/attribute-hyphenation -->
|
||||
@@ -88,6 +224,7 @@ onMounted(setCommandBarData);
|
||||
noAutoLoadMdIcons
|
||||
hideBreadcrumbs
|
||||
:placeholder="placeholder"
|
||||
@change="onCommandBarChange"
|
||||
@selected="onSelected"
|
||||
@closed="onClosed"
|
||||
/>
|
||||
|
||||
@@ -22,6 +22,7 @@ const allowedLocales = computed(() => {
|
||||
id: locale?.code,
|
||||
name: allLocales[locale?.code],
|
||||
code: locale?.code,
|
||||
isDraft: locale?.draft || false,
|
||||
articlesCount: locale?.articles_count || 0,
|
||||
categoriesCount: locale?.categories_count || 0,
|
||||
};
|
||||
|
||||
@@ -69,6 +69,8 @@ export default {
|
||||
onCmdSnoozeNotification(snoozeType) {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
this.showCustomSnoozeModal = true;
|
||||
} else if (typeof snoozeType === 'number') {
|
||||
this.snoozeNotification(snoozeType);
|
||||
} else {
|
||||
const snoozedUntil = findSnoozeTime(snoozeType) || null;
|
||||
this.snoozeNotification(snoozedUntil);
|
||||
|
||||
@@ -99,6 +99,7 @@ export default {
|
||||
healthData: null,
|
||||
isLoadingHealth: false,
|
||||
healthError: null,
|
||||
isRegisteringWebhook: false,
|
||||
widgetBubblePosition: 'right',
|
||||
widgetBubbleType: 'standard',
|
||||
widgetBubbleLauncherTitle: '',
|
||||
@@ -217,13 +218,10 @@ export default {
|
||||
return getInboxIconByType(type, medium, 'line');
|
||||
},
|
||||
bannerMaxWidth() {
|
||||
const narrowTabs = [
|
||||
'collaborators',
|
||||
'configuration',
|
||||
'bot-configuration',
|
||||
];
|
||||
const narrowTabs = ['collaborators', 'bot-configuration'];
|
||||
const wideIfWebWidget = ['configuration', 'inbox-settings'];
|
||||
if (narrowTabs.includes(this.selectedTabKey)) return 'max-w-4xl';
|
||||
if (this.selectedTabKey === 'inbox-settings') {
|
||||
if (wideIfWebWidget.includes(this.selectedTabKey)) {
|
||||
return this.isAWebWidgetInbox ? 'max-w-7xl' : 'max-w-4xl';
|
||||
}
|
||||
return 'max-w-7xl';
|
||||
@@ -353,6 +351,8 @@ export default {
|
||||
this.$nextTick(() => {
|
||||
this.setTabFromRouteParam();
|
||||
});
|
||||
} else {
|
||||
this.selectedFeatureFlags = newInbox?.selected_feature_flags || [];
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
@@ -424,6 +424,23 @@ export default {
|
||||
this.isLoadingHealth = false;
|
||||
}
|
||||
},
|
||||
async registerWebhook() {
|
||||
if (!this.inbox) return;
|
||||
|
||||
try {
|
||||
this.isRegisteringWebhook = true;
|
||||
await InboxHealthAPI.registerWebhook(this.inbox.id);
|
||||
useAlert(this.$t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.REGISTER_SUCCESS'));
|
||||
await this.fetchHealthData();
|
||||
} catch (error) {
|
||||
useAlert(
|
||||
error.message ||
|
||||
this.$t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.REGISTER_ERROR')
|
||||
);
|
||||
} finally {
|
||||
this.isRegisteringWebhook = false;
|
||||
}
|
||||
},
|
||||
handleFeatureFlag(e) {
|
||||
this.selectedFeatureFlags = this.toggleInput(
|
||||
this.selectedFeatureFlags,
|
||||
@@ -1146,7 +1163,11 @@ export default {
|
||||
<div v-if="selectedTabKey === 'collaborators'" class="mx-6 max-w-4xl">
|
||||
<CollaboratorsPage :inbox="inbox" />
|
||||
</div>
|
||||
<div v-if="selectedTabKey === 'configuration'" class="mx-6 max-w-4xl">
|
||||
<div
|
||||
v-if="selectedTabKey === 'configuration'"
|
||||
class="mx-6"
|
||||
:class="isAWebWidgetInbox ? 'max-w-7xl' : 'max-w-4xl'"
|
||||
>
|
||||
<ConfigurationPage :inbox="inbox" />
|
||||
</div>
|
||||
<div v-if="selectedTabKey === 'csat'">
|
||||
@@ -1162,7 +1183,11 @@ export default {
|
||||
<BotConfiguration :inbox="inbox" />
|
||||
</div>
|
||||
<div v-if="selectedTabKey === 'whatsapp-health'">
|
||||
<AccountHealth :health-data="healthData" />
|
||||
<AccountHealth
|
||||
:health-data="healthData"
|
||||
:is-registering-webhook="isRegisteringWebhook"
|
||||
@register-webhook="registerWebhook"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -10,8 +10,14 @@ const props = defineProps({
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
isRegisteringWebhook: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['registerWebhook']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const QUALITY_COLORS = {
|
||||
@@ -133,6 +139,28 @@ const formatModeDisplay = mode =>
|
||||
const getModeStatusTextColor = mode => MODE_COLORS[mode] || 'text-n-slate-12';
|
||||
|
||||
const getStatusTextColor = status => STATUS_COLORS[status] || 'text-n-slate-12';
|
||||
|
||||
const showWebhookSection = computed(
|
||||
() => props.healthData?.webhook_configuration !== undefined
|
||||
);
|
||||
|
||||
const webhookUrl = computed(
|
||||
() =>
|
||||
props.healthData?.webhook_configuration?.whatsapp_business_account ||
|
||||
props.healthData?.webhook_configuration?.application
|
||||
);
|
||||
|
||||
const webhookConfigured = computed(() => !!webhookUrl.value);
|
||||
|
||||
const webhookUrlMismatch = computed(
|
||||
() =>
|
||||
webhookConfigured.value &&
|
||||
webhookUrl.value !== props.healthData?.expected_webhook_url
|
||||
);
|
||||
|
||||
const handleRegisterWebhook = () => {
|
||||
emit('registerWebhook');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -211,6 +239,55 @@ const getStatusTextColor = status => STATUS_COLORS[status] || 'text-n-slate-12';
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Webhook configuration card -->
|
||||
<div
|
||||
v-if="showWebhookSection"
|
||||
class="flex flex-col gap-2 p-4 rounded-lg border border-n-weak bg-n-solid-1"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<span class="text-body-main font-medium text-n-slate-11">
|
||||
{{ t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.TITLE') }}
|
||||
</span>
|
||||
<Icon
|
||||
v-tooltip.top="t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.DESCRIPTION')"
|
||||
icon="i-lucide-info"
|
||||
class="flex-shrink-0 w-4 h-4 cursor-help text-n-slate-9"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<span
|
||||
v-if="webhookConfigured && !webhookUrlMismatch"
|
||||
class="inline-flex items-center gap-1.5 px-2 py-0.5 min-h-6 text-label-small rounded-md bg-n-alpha-2 text-n-teal-11"
|
||||
>
|
||||
<Icon icon="i-lucide-check-circle" class="w-3.5 h-3.5" />
|
||||
{{ t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.CONFIGURED_SUCCESS') }}
|
||||
</span>
|
||||
<span
|
||||
v-else
|
||||
class="inline-flex items-center gap-1.5 px-2 py-0.5 min-h-6 text-label-small rounded-md bg-n-alpha-2 text-n-amber-11"
|
||||
>
|
||||
<Icon icon="i-lucide-alert-triangle" class="w-3.5 h-3.5" />
|
||||
{{
|
||||
webhookUrlMismatch
|
||||
? t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.URL_MISMATCH')
|
||||
: t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.ACTION_REQUIRED')
|
||||
}}
|
||||
</span>
|
||||
<ButtonV4
|
||||
v-if="!webhookConfigured || webhookUrlMismatch"
|
||||
sm
|
||||
solid
|
||||
blue
|
||||
:loading="isRegisteringWebhook"
|
||||
:disabled="isRegisteringWebhook"
|
||||
class="flex-shrink-0"
|
||||
@click="handleRegisterWebhook"
|
||||
>
|
||||
{{ t('INBOX_MGMT.ACCOUNT_HEALTH.WEBHOOK.REGISTER_BUTTON') }}
|
||||
</ButtonV4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="pt-8">
|
||||
|
||||
+117
-66
@@ -2,6 +2,8 @@
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||
import SettingsFieldSection from 'dashboard/components-next/Settings/SettingsFieldSection.vue';
|
||||
import SettingsToggleSection from 'dashboard/components-next/Settings/SettingsToggleSection.vue';
|
||||
import SettingsAccordion from 'dashboard/components-next/Settings/SettingsAccordion.vue';
|
||||
import ImapSettings from '../ImapSettings.vue';
|
||||
import SmtpSettings from '../SmtpSettings.vue';
|
||||
import { useVuelidate } from '@vuelidate/core';
|
||||
@@ -14,6 +16,8 @@ import { sanitizeAllowedDomains } from 'dashboard/helper/URLHelper';
|
||||
export default {
|
||||
components: {
|
||||
SettingsFieldSection,
|
||||
SettingsToggleSection,
|
||||
SettingsAccordion,
|
||||
ImapSettings,
|
||||
SmtpSettings,
|
||||
NextButton,
|
||||
@@ -33,12 +37,14 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
hmacMandatory: false,
|
||||
allowMobileWebview: false,
|
||||
whatsAppInboxAPIKey: '',
|
||||
isRequestingReauthorization: false,
|
||||
isSyncingTemplates: false,
|
||||
allowedDomains: '',
|
||||
isUpdatingAllowedDomains: false,
|
||||
callingEnabled: false,
|
||||
isSettingDefaults: false,
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
@@ -59,16 +65,30 @@ export default {
|
||||
inbox() {
|
||||
this.setDefaults();
|
||||
},
|
||||
allowMobileWebview() {
|
||||
if (!this.isSettingDefaults) this.handleMobileWebviewFlag();
|
||||
},
|
||||
hmacMandatory() {
|
||||
if (!this.isSettingDefaults && this.isAWebWidgetInbox)
|
||||
this.handleHmacFlag();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setDefaults();
|
||||
},
|
||||
methods: {
|
||||
setDefaults() {
|
||||
this.isSettingDefaults = true;
|
||||
this.hmacMandatory = this.inbox.hmac_mandatory || false;
|
||||
this.allowMobileWebview = (
|
||||
this.inbox.selected_feature_flags || []
|
||||
).includes('allow_mobile_webview');
|
||||
this.allowedDomains = this.inbox.allowed_domains || '';
|
||||
this.callingEnabled =
|
||||
this.inbox.provider_config?.calling_enabled || false;
|
||||
this.$nextTick(() => {
|
||||
this.isSettingDefaults = false;
|
||||
});
|
||||
},
|
||||
handleHmacFlag() {
|
||||
this.updateInbox();
|
||||
@@ -88,6 +108,26 @@ export default {
|
||||
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
|
||||
}
|
||||
},
|
||||
async handleMobileWebviewFlag() {
|
||||
try {
|
||||
const currentFlags = this.inbox.selected_feature_flags || [];
|
||||
const selectedFlags = this.allowMobileWebview
|
||||
? [...currentFlags, 'allow_mobile_webview']
|
||||
: currentFlags.filter(f => f !== 'allow_mobile_webview');
|
||||
|
||||
const payload = {
|
||||
id: this.inbox.id,
|
||||
formData: false,
|
||||
channel: {
|
||||
selected_feature_flags: selectedFlags,
|
||||
},
|
||||
};
|
||||
await this.$store.dispatch('inboxes/updateInbox', payload);
|
||||
useAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
|
||||
}
|
||||
},
|
||||
async updateAllowedDomains() {
|
||||
this.isUpdatingAllowedDomains = true;
|
||||
const sanitizedAllowedDomains = sanitizeAllowedDomains(
|
||||
@@ -216,75 +256,86 @@ export default {
|
||||
</SettingsFieldSection>
|
||||
</div>
|
||||
<div v-else-if="isAWebWidgetInbox">
|
||||
<div>
|
||||
<SettingsFieldSection
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.ALLOWED_DOMAINS.TITLE')"
|
||||
:help-text="$t('INBOX_MGMT.SETTINGS_POPUP.ALLOWED_DOMAINS.SUBTITLE')"
|
||||
class="[&>div]:!items-start"
|
||||
<div class="space-y-4">
|
||||
<SettingsToggleSection
|
||||
:header="$t('INBOX_MGMT.SETTINGS_POPUP.ALLOWED_DOMAINS.TITLE')"
|
||||
:description="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.ALLOWED_DOMAINS.DESCRIPTION')
|
||||
"
|
||||
hide-toggle
|
||||
>
|
||||
<TextArea
|
||||
v-model="allowedDomains"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.ALLOWED_DOMAINS.PLACEHOLDER')
|
||||
"
|
||||
auto-height
|
||||
min-height="8rem"
|
||||
class="w-full"
|
||||
/>
|
||||
<template #extra>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-8">
|
||||
<div class="col-span-1 lg:col-span-2 invisible" />
|
||||
<div class="col-span-1 lg:col-span-6 mt-4 justify-self-end">
|
||||
<NextButton
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
||||
:is-loading="isUpdatingAllowedDomains"
|
||||
@click="updateAllowedDomains"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</SettingsFieldSection>
|
||||
|
||||
<SettingsFieldSection
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_VERIFICATION')"
|
||||
>
|
||||
<woot-code :script="inbox.hmac_token" />
|
||||
<template #extra>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-8">
|
||||
<div class="col-span-1 lg:col-span-2 invisible" />
|
||||
<p
|
||||
class="col-span-1 lg:col-span-6 mt-1.5 text-label-small text-n-slate-11 ltr:ml-1 rtl:mr-1"
|
||||
>
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.HMAC_DESCRIPTION') }}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://www.chatwoot.com/docs/product/channels/live-chat/sdk/identity-validation/"
|
||||
class="text-n-blue-11 hover:underline text-label-small"
|
||||
>
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.HMAC_LINK_TO_DOCS') }}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</SettingsFieldSection>
|
||||
<SettingsFieldSection
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
|
||||
:help-text="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')"
|
||||
>
|
||||
<div class="flex gap-2 items-center">
|
||||
<input
|
||||
id="hmacMandatory"
|
||||
v-model="hmacMandatory"
|
||||
type="checkbox"
|
||||
@change="handleHmacFlag"
|
||||
<template #editor>
|
||||
<TextArea
|
||||
v-model="allowedDomains"
|
||||
:placeholder="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.ALLOWED_DOMAINS.PLACEHOLDER')
|
||||
"
|
||||
auto-height
|
||||
resize
|
||||
class="w-full [&>div]:!bg-transparent [&>div]:!border-none [&>div]:!border-0 [&>div]:px-0 [&>div]:pb-0 [&>div]:pt-0"
|
||||
/>
|
||||
<label for="hmacMandatory" class="text-body-main text-n-slate-12">
|
||||
{{ $t('INBOX_MGMT.EDIT.ENABLE_HMAC.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
</SettingsFieldSection>
|
||||
<div class="mt-3 flex justify-end">
|
||||
<NextButton
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
||||
:is-loading="isUpdatingAllowedDomains"
|
||||
@click="updateAllowedDomains"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</SettingsToggleSection>
|
||||
<SettingsToggleSection
|
||||
v-model="allowMobileWebview"
|
||||
:header="$t('INBOX_MGMT.SETTINGS_POPUP.ALLOW_MOBILE_WEBVIEW.LABEL')"
|
||||
:description="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.ALLOW_MOBILE_WEBVIEW.SUBTITLE')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SettingsAccordion
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.TITLE')"
|
||||
class="mt-6"
|
||||
>
|
||||
<SettingsToggleSection
|
||||
:header="$t('INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.TITLE')"
|
||||
:description="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.DESCRIPTION')
|
||||
"
|
||||
hide-toggle
|
||||
>
|
||||
<template #editor>
|
||||
<p class="mb-1 text-sm font-medium text-n-slate-12">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.SECRET_KEY') }}
|
||||
</p>
|
||||
<woot-code :script="inbox.hmac_token" />
|
||||
<p class="mt-1.5 text-label-small text-n-slate-11">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.HMAC_DESCRIPTION') }}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href="https://www.chatwoot.com/docs/product/channels/live-chat/sdk/identity-validation/"
|
||||
class="text-n-blue-11 hover:underline text-label-small"
|
||||
>
|
||||
{{
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.VIEW_DOCS')
|
||||
}}
|
||||
</a>
|
||||
</p>
|
||||
</template>
|
||||
</SettingsToggleSection>
|
||||
|
||||
<SettingsToggleSection
|
||||
v-model="hmacMandatory"
|
||||
:header="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.REQUIRE_LABEL')
|
||||
"
|
||||
:description="
|
||||
$t(
|
||||
'INBOX_MGMT.SETTINGS_POPUP.IDENTITY_VALIDATION.REQUIRE_DESCRIPTION'
|
||||
)
|
||||
"
|
||||
/>
|
||||
</SettingsAccordion>
|
||||
</div>
|
||||
<div v-else-if="isAPIInbox">
|
||||
<SettingsFieldSection
|
||||
|
||||
Reference in New Issue
Block a user