feat: Add a dedicated home for agents and admins
This commit is contained in:
@@ -4,6 +4,7 @@ import { provideSidebarContext, useSidebarResize } from './provider';
|
||||
import { useAccount } from 'dashboard/composables/useAccount';
|
||||
import { useKbd } from 'dashboard/composables/utils/useKbd';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||
import { useStore } from 'vuex';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useSidebarKeyboardShortcuts } from './useSidebarKeyboardShortcuts';
|
||||
@@ -40,6 +41,16 @@ const { accountScopedRoute, isOnChatwootCloud } = useAccount();
|
||||
const store = useStore();
|
||||
const searchShortcut = useKbd([`$mod`, 'k']);
|
||||
const { t } = useI18n();
|
||||
const { uiSettings } = useUISettings();
|
||||
const isHomeDashboardEnabled = computed(
|
||||
() => !!uiSettings.value?.home_dashboard_enabled
|
||||
);
|
||||
const unreadInboxCount = useMapGetter('notifications/getUnreadCount');
|
||||
const unreadInboxCountLabel = computed(() => {
|
||||
const count = unreadInboxCount.value;
|
||||
if (!count) return '';
|
||||
return count < 100 ? String(count) : '99+';
|
||||
});
|
||||
|
||||
const isACustomBrandedInstance = useMapGetter(
|
||||
'globalConfig/isACustomBrandedInstance'
|
||||
@@ -212,16 +223,28 @@ const reportRoutes = computed(() => newReportRoutes());
|
||||
|
||||
const menuItems = computed(() => {
|
||||
return [
|
||||
{
|
||||
name: 'Inbox',
|
||||
label: t('SIDEBAR.INBOX'),
|
||||
icon: 'i-lucide-inbox',
|
||||
to: accountScopedRoute('inbox_view'),
|
||||
activeOn: ['inbox_view', 'inbox_view_conversation'],
|
||||
getterKeys: {
|
||||
count: 'notifications/getUnreadCount',
|
||||
},
|
||||
},
|
||||
...(isHomeDashboardEnabled.value
|
||||
? [
|
||||
{
|
||||
name: 'Home',
|
||||
label: t('SIDEBAR.HOME'),
|
||||
icon: 'i-lucide-gauge',
|
||||
to: accountScopedRoute('home_dashboard'),
|
||||
activeOn: ['home_dashboard', 'home_dashboard_admin'],
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
name: 'Inbox',
|
||||
label: t('SIDEBAR.INBOX'),
|
||||
icon: 'i-lucide-inbox',
|
||||
to: accountScopedRoute('inbox_view'),
|
||||
activeOn: ['inbox_view', 'inbox_view_conversation'],
|
||||
getterKeys: {
|
||||
count: 'notifications/getUnreadCount',
|
||||
},
|
||||
},
|
||||
]),
|
||||
{
|
||||
name: 'Conversation',
|
||||
label: t('SIDEBAR.CONVERSATIONS'),
|
||||
@@ -858,6 +881,20 @@ const menuItems = computed(() => {
|
||||
:is-collapsed="isEffectivelyCollapsed"
|
||||
@open-key-shortcut-modal="emit('openKeyShortcutModal')"
|
||||
/>
|
||||
<RouterLink
|
||||
v-if="isHomeDashboardEnabled"
|
||||
:to="accountScopedRoute('inbox_view')"
|
||||
:title="t('SIDEBAR.INBOX')"
|
||||
class="size-8 rounded-lg hover:bg-n-alpha-1 flex-shrink-0 grid place-content-center relative text-n-slate-11"
|
||||
>
|
||||
<span class="i-lucide-bell size-4" />
|
||||
<span
|
||||
v-if="unreadInboxCountLabel"
|
||||
class="min-h-2 min-w-2 p-0.5 px-1 bg-n-ruby-9 rounded-lg absolute -top-1 -right-1.5 grid place-items-center text-[9px] leading-none text-n-ruby-3"
|
||||
>
|
||||
{{ unreadInboxCountLabel }}
|
||||
</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Resize Handle (desktop only) -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"INBOX": {
|
||||
"LIST": {
|
||||
"TITLE": "My Inbox",
|
||||
"TITLE": "Notifications",
|
||||
"DISPLAY_DROPDOWN": "Display",
|
||||
"LOADING": "Fetching notifications",
|
||||
"404": "There are no active notifications in this group.",
|
||||
|
||||
@@ -58,6 +58,10 @@
|
||||
"UPDATE_SUCCESS": "Your Language settings have been updated successfully",
|
||||
"UPDATE_ERROR": "There is an error while updating the language settings, please try again",
|
||||
"USE_ACCOUNT_DEFAULT": "Use account default"
|
||||
},
|
||||
"HOME_DASHBOARD": {
|
||||
"TITLE": "Home dashboard",
|
||||
"NOTE": "Show a Home dashboard with team workload, KPIs, and a Captain prompt as your landing page. Hides the My Inbox sidebar item."
|
||||
}
|
||||
},
|
||||
"MESSAGE_SIGNATURE_SECTION": {
|
||||
@@ -228,6 +232,128 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"HOME_DASHBOARD_PAGE": {
|
||||
"ROLE_SWITCH": {
|
||||
"AGENT": "Agent",
|
||||
"ADMIN": "Admin"
|
||||
},
|
||||
"GREETING": {
|
||||
"MORNING": "Good morning",
|
||||
"AFTERNOON": "Good afternoon",
|
||||
"EVENING": "Good evening",
|
||||
"LATE": "Working late",
|
||||
"FALLBACK_NAME": "there",
|
||||
"GREETING_LINE": "{greeting}, ",
|
||||
"NAME_LINE": "{name}."
|
||||
},
|
||||
"TEAM_SUMMARY": {
|
||||
"PREFIX": "Your team has ",
|
||||
"OPEN_CONVERSATIONS": "{count} open conversations",
|
||||
"MID": ", ",
|
||||
"NEARING_SLA": "{count} nearing SLA",
|
||||
"AND": ", and ",
|
||||
"AGENTS_ONLINE": "{count} agents online",
|
||||
"PERIOD": "."
|
||||
},
|
||||
"AGENT_SUMMARY": {
|
||||
"PREFIX": "You have ",
|
||||
"OPEN_CONVERSATIONS": "{count} open conversations",
|
||||
"MID": ", ",
|
||||
"UNATTENDED": "{count} unattended",
|
||||
"AND": ", and ",
|
||||
"NEARING_SLA": "{count} close to SLA breach",
|
||||
"PERIOD": "."
|
||||
},
|
||||
"KPI": {
|
||||
"OPEN_CONVERSATIONS": "Open conversations",
|
||||
"AVG_FIRST_RESPONSE": "Avg first response",
|
||||
"FIRST_RESPONSE": "First response",
|
||||
"RESOLVED_TODAY": "Resolved today",
|
||||
"NOTIFICATIONS": "Notifications",
|
||||
"SLA_BREACHES_TODAY": "SLA breaches today",
|
||||
"TEAM_CSAT_TODAY": "Team CSAT today",
|
||||
"SEE_ALL": "See all"
|
||||
},
|
||||
"AI": {
|
||||
"SHORTCUT": "⌘K"
|
||||
},
|
||||
"TEAM_WORKLOAD": {
|
||||
"TITLE": "Team workload",
|
||||
"SORT_BY": "Sort by",
|
||||
"HEADERS": {
|
||||
"AGENT": "Agent",
|
||||
"WORKLOAD": "Workload",
|
||||
"UNATTENDED_OPEN": "Unattended / Open",
|
||||
"FRT": "FRT",
|
||||
"CSAT": "CSAT"
|
||||
},
|
||||
"OFF_SHIFT": "Off shift",
|
||||
"CAPACITY": "{percent}% capacity",
|
||||
"YOU": "YOU"
|
||||
},
|
||||
"ATTENTION": {
|
||||
"TITLE": "Needs your attention",
|
||||
"SUBTITLE": "3 items, surfaced by Captain"
|
||||
},
|
||||
"SUGGESTIONS_ADMIN": {
|
||||
"OVERLOADED": "Who's overloaded right now?",
|
||||
"HIGH_VOLUME": "What's driving the {count} open conversations today?",
|
||||
"CSAT_OUTLIERS": "Show CSAT outliers this week",
|
||||
"TEAM_PERFORMANCE": "Summarize team performance today",
|
||||
"COACH_AGENT": "Draft a coaching note for {name}",
|
||||
"QUIET_DAY": "What did the team accomplish today?",
|
||||
"FIND_PATTERNS": "Trending customer questions"
|
||||
},
|
||||
"SUGGESTIONS_AGENT": {
|
||||
"SUMMARIZE_QUEUE": "Summarize my queue",
|
||||
"TRIAGE_UNATTENDED": "Help me triage my {count} unattended",
|
||||
"NEAR_SLA": "Which of my conversations are close to SLA breach?",
|
||||
"URGENT": "What's most urgent right now?",
|
||||
"SUMMARIZE_CONVERSATION": "Summarize my conversation with {name}",
|
||||
"CATCH_UP": "Catch me up on what I missed",
|
||||
"SLOW_DAY": "What can I work on?"
|
||||
},
|
||||
"AI_PLACEHOLDERS_ADMIN": {
|
||||
"DEFAULT": "Ask Captain about your team…",
|
||||
"SUMMARIZE": "Summarize the three most urgent tickets…",
|
||||
"DRAFT_REPLY": "Draft a refund reply for Aria Chen…",
|
||||
"WHY_CSAT": "Why did CSAT slip today?",
|
||||
"FIND_TICKETS": "Find tickets mentioning rate limit this week…"
|
||||
},
|
||||
"AI_PLACEHOLDERS_AGENT": {
|
||||
"DEFAULT": "Ask anything about your queue…",
|
||||
"SUMMARIZE": "Summarize the three most urgent tickets…",
|
||||
"DRAFT_REPLY": "Draft a refund reply for Aria Chen…",
|
||||
"WHY_CSAT": "Why did CSAT slip today?",
|
||||
"FIND_TICKETS": "Find tickets mentioning rate limit this week…"
|
||||
},
|
||||
"SORT_OPTIONS_ADMIN": {
|
||||
"CAPACITY": "Capacity",
|
||||
"FIRST_RESPONSE": "First response",
|
||||
"CSAT_TODAY": "CSAT today",
|
||||
"RESOLVED_TODAY": "Resolved today"
|
||||
},
|
||||
"SORT_OPTIONS_AGENT": {
|
||||
"PRIORITY": "Priority",
|
||||
"SLA_BREACH": "SLA breach",
|
||||
"LATEST": "Latest activity",
|
||||
"OLDEST": "Oldest first",
|
||||
"CUSTOMER": "Customer name"
|
||||
},
|
||||
"TOP_CONVERSATIONS": {
|
||||
"TITLE": "Top conversations",
|
||||
"SLA_LEFT": "{time} left",
|
||||
"EMPTY": "Nothing in your queue.",
|
||||
"LOADING": "Loading…"
|
||||
},
|
||||
"COPILOT_THREAD": {
|
||||
"BACK": "Back to home",
|
||||
"SEND": "Send"
|
||||
},
|
||||
"RECENT_THREADS": {
|
||||
"TITLE": "Recent threads"
|
||||
}
|
||||
},
|
||||
"SIDEBAR_ITEMS": {
|
||||
"CHANGE_AVAILABILITY_STATUS": "Change",
|
||||
"CHANGE_ACCOUNTS": "Switch account",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { routes as contactRoutes } from './contacts/routes';
|
||||
import { routes as companyRoutes } from './companies/routes';
|
||||
import { routes as notificationRoutes } from './notifications/routes';
|
||||
import { routes as inboxRoutes } from './inbox/routes';
|
||||
import { routes as homeRoutes } from './home/routes';
|
||||
import { frontendURL } from '../../helper/URLHelper';
|
||||
import helpcenterRoutes from './helpcenter/helpcenter.routes';
|
||||
import campaignsRoutes from './campaigns/campaigns.routes';
|
||||
@@ -21,6 +22,7 @@ export default {
|
||||
component: AppContainer,
|
||||
children: [
|
||||
...captainRoutes,
|
||||
...homeRoutes,
|
||||
...inboxRoutes,
|
||||
...conversation.routes,
|
||||
...settings.routes,
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import { useStore, useMapGetter } from 'dashboard/composables/store';
|
||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||
import { useAccount } from 'dashboard/composables/useAccount';
|
||||
import CopilotMessagesAPI from 'dashboard/api/captain/copilotMessages';
|
||||
import CopilotAgentMessage from 'dashboard/components-next/copilot/CopilotAgentMessage.vue';
|
||||
import CopilotAssistantMessage from 'dashboard/components-next/copilot/CopilotAssistantMessage.vue';
|
||||
import CopilotThinkingGroup from 'dashboard/components-next/copilot/CopilotThinkingGroup.vue';
|
||||
import CopilotLoader from 'dashboard/components-next/copilot/CopilotLoader.vue';
|
||||
import CopilotInput from 'dashboard/components-next/copilot/CopilotInput.vue';
|
||||
import ToggleCopilotAssistant from 'dashboard/components-next/copilot/ToggleCopilotAssistant.vue';
|
||||
|
||||
const props = defineProps({
|
||||
threadId: {
|
||||
type: [String, Number],
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
const { uiSettings, updateUISettings } = useUISettings();
|
||||
const { accountScopedRoute } = useAccount();
|
||||
|
||||
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||
|
||||
const messages = computed(() =>
|
||||
store.getters['copilotMessages/getMessagesByThreadId'](props.threadId)
|
||||
);
|
||||
|
||||
const activeAssistant = computed(() => {
|
||||
const preferredId = uiSettings.value.preferred_captain_assistant_id;
|
||||
if (preferredId) {
|
||||
const found = assistants.value.find(a => a.id === preferredId);
|
||||
if (found) return found;
|
||||
}
|
||||
return assistants.value[0];
|
||||
});
|
||||
|
||||
const setAssistant = async assistant => {
|
||||
await updateUISettings({
|
||||
preferred_captain_assistant_id: assistant.id,
|
||||
});
|
||||
};
|
||||
|
||||
const sendMessage = async message => {
|
||||
try {
|
||||
await store.dispatch('copilotMessages/create', {
|
||||
assistant_id: activeAssistant.value?.id,
|
||||
threadId: props.threadId,
|
||||
message,
|
||||
});
|
||||
} catch (error) {
|
||||
useAlert(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
const goHome = () => {
|
||||
router.push(accountScopedRoute('home_dashboard'));
|
||||
};
|
||||
|
||||
const groupedMessages = computed(() => {
|
||||
const result = [];
|
||||
let thinkingGroup = [];
|
||||
messages.value.forEach(message => {
|
||||
if (message.message_type === 'assistant_thinking') {
|
||||
thinkingGroup.push(message);
|
||||
} else {
|
||||
if (thinkingGroup.length) {
|
||||
result.push({
|
||||
id: thinkingGroup[0].id,
|
||||
message_type: 'thinking_group',
|
||||
messages: thinkingGroup,
|
||||
});
|
||||
thinkingGroup = [];
|
||||
}
|
||||
result.push(message);
|
||||
}
|
||||
});
|
||||
if (thinkingGroup.length) {
|
||||
result.push({
|
||||
id: thinkingGroup[0].id,
|
||||
message_type: 'thinking_group',
|
||||
messages: thinkingGroup,
|
||||
});
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
const isLastMessageFromAssistant = computed(() => {
|
||||
const last = groupedMessages.value[groupedMessages.value.length - 1];
|
||||
return last?.message_type === 'assistant';
|
||||
});
|
||||
|
||||
const chatContainer = ref(null);
|
||||
const scrollToBottom = async () => {
|
||||
await nextTick();
|
||||
if (chatContainer.value) {
|
||||
chatContainer.value.scrollTop = chatContainer.value.scrollHeight;
|
||||
}
|
||||
};
|
||||
|
||||
watch(() => messages.value, scrollToBottom, { deep: true });
|
||||
|
||||
onMounted(async () => {
|
||||
store.dispatch('captainAssistants/get');
|
||||
try {
|
||||
const { data } = await CopilotMessagesAPI.get(props.threadId);
|
||||
const payload = data?.payload || [];
|
||||
payload.forEach(message => {
|
||||
store.dispatch('copilotMessages/upsert', message);
|
||||
});
|
||||
scrollToBottom();
|
||||
} catch {
|
||||
// best-effort fetch; rely on websocket if API errors
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="flex flex-col w-full h-full bg-n-surface-1 text-n-slate-12">
|
||||
<div
|
||||
class="flex items-center gap-2 px-6 py-3 border-b border-n-weak flex-shrink-0"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center gap-1.5 h-8 px-2.5 rounded-md text-[13px] font-medium text-n-slate-11 hover:text-n-slate-12 hover:bg-n-alpha-2 transition-colors bg-transparent border-0 cursor-pointer"
|
||||
@click="goHome"
|
||||
>
|
||||
<span class="i-lucide-chevron-left size-4" />
|
||||
{{ $t('HOME_DASHBOARD_PAGE.COPILOT_THREAD.BACK') }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
ref="chatContainer"
|
||||
class="flex-1 min-h-0 w-full overflow-y-auto text-sm leading-6 tracking-tight"
|
||||
>
|
||||
<div class="w-full max-w-[820px] mx-auto px-6 py-6">
|
||||
<div
|
||||
v-if="groupedMessages.length"
|
||||
class="space-y-6 flex flex-col w-full"
|
||||
>
|
||||
<template v-for="(item, index) in groupedMessages" :key="item.id">
|
||||
<CopilotAgentMessage
|
||||
v-if="item.message_type === 'user'"
|
||||
:message="item.message"
|
||||
/>
|
||||
<CopilotAssistantMessage
|
||||
v-else-if="item.message_type === 'assistant'"
|
||||
:message="item.message"
|
||||
:is-last-message="index === groupedMessages.length - 1"
|
||||
conversation-inbox-type=""
|
||||
/>
|
||||
<CopilotThinkingGroup
|
||||
v-else
|
||||
:messages="item.messages"
|
||||
:default-collapsed="isLastMessageFromAssistant"
|
||||
/>
|
||||
</template>
|
||||
<CopilotLoader v-if="!isLastMessageFromAssistant" />
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="flex items-center justify-center h-full text-sm text-n-slate-10"
|
||||
>
|
||||
{{ $t('HOME_DASHBOARD_PAGE.TOP_CONVERSATIONS.LOADING') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full flex-shrink-0">
|
||||
<div class="w-full max-w-[820px] mx-auto px-6 pt-px pb-4">
|
||||
<div class="flex items-center justify-between gap-2 mb-1">
|
||||
<ToggleCopilotAssistant
|
||||
v-if="assistants.length > 1"
|
||||
:assistants="assistants"
|
||||
:active-assistant="activeAssistant || {}"
|
||||
@set-assistant="setAssistant"
|
||||
/>
|
||||
<div v-else />
|
||||
</div>
|
||||
<CopilotInput
|
||||
v-if="assistants.length"
|
||||
class="w-full"
|
||||
@send="sendMessage"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
import { frontendURL } from 'dashboard/helper/URLHelper';
|
||||
import { ROLES } from 'dashboard/constants/permissions.js';
|
||||
import HomeDashboard from './HomeDashboard.vue';
|
||||
import HomeCopilotThread from './HomeCopilotThread.vue';
|
||||
|
||||
export const routes = [
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/home'),
|
||||
name: 'home_dashboard',
|
||||
component: HomeDashboard,
|
||||
meta: {
|
||||
permissions: ROLES,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/home/admin'),
|
||||
name: 'home_dashboard_admin',
|
||||
component: HomeDashboard,
|
||||
meta: {
|
||||
permissions: ['administrator'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: frontendURL('accounts/:accountId/home/copilot/:threadId'),
|
||||
name: 'home_copilot_thread',
|
||||
component: HomeCopilotThread,
|
||||
props: true,
|
||||
meta: {
|
||||
permissions: ROLES,
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -13,6 +13,7 @@ import UserBasicDetails from './UserBasicDetails.vue';
|
||||
import MessageSignature from './MessageSignature.vue';
|
||||
import FontSize from './FontSize.vue';
|
||||
import UserLanguageSelect from './UserLanguageSelect.vue';
|
||||
import SettingsToggleSection from 'dashboard/components-next/Settings/SettingsToggleSection.vue';
|
||||
import HotKeyCard from './HotKeyCard.vue';
|
||||
import ChangePassword from './ChangePassword.vue';
|
||||
import NotificationPreferences from './NotificationPreferences.vue';
|
||||
@@ -43,13 +44,16 @@ export default {
|
||||
AccessToken,
|
||||
MfaSettingsCard,
|
||||
BaseSettingsHeader,
|
||||
SettingsToggleSection,
|
||||
},
|
||||
setup() {
|
||||
const { isEditorHotKeyEnabled, updateUISettings } = useUISettings();
|
||||
const { uiSettings, isEditorHotKeyEnabled, updateUISettings } =
|
||||
useUISettings();
|
||||
const { currentFontSize, updateFontSize } = useFontSize();
|
||||
const { replaceInstallationName } = useBranding();
|
||||
|
||||
return {
|
||||
uiSettings,
|
||||
currentFontSize,
|
||||
updateFontSize,
|
||||
isEditorHotKeyEnabled,
|
||||
@@ -103,6 +107,14 @@ export default {
|
||||
isMfaEnabled() {
|
||||
return parseBoolean(window.chatwootConfig?.isMfaEnabled);
|
||||
},
|
||||
homeDashboardEnabled: {
|
||||
get() {
|
||||
return !!this.uiSettings?.home_dashboard_enabled;
|
||||
},
|
||||
set(value) {
|
||||
this.updateUISettings({ home_dashboard_enabled: value });
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.currentUserId) {
|
||||
@@ -248,6 +260,16 @@ export default {
|
||||
$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.LANGUAGE.NOTE')
|
||||
"
|
||||
/>
|
||||
<SettingsToggleSection
|
||||
v-model="homeDashboardEnabled"
|
||||
class="w-full"
|
||||
:header="
|
||||
$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.HOME_DASHBOARD.TITLE')
|
||||
"
|
||||
:description="
|
||||
$t('PROFILE_SETTINGS.FORM.INTERFACE_SECTION.HOME_DASHBOARD.NOTE')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</SectionLayout>
|
||||
<SectionLayout
|
||||
|
||||
@@ -39,7 +39,9 @@ export const validateAuthenticateRoutePermission = async (to, next) => {
|
||||
isActive;
|
||||
|
||||
if (to.name === 'no_accounts' || !to.name) {
|
||||
const target = needsOnboarding ? 'onboarding' : 'dashboard';
|
||||
const homeDashboardEnabled = !!user?.ui_settings?.home_dashboard_enabled;
|
||||
const landingTarget = homeDashboardEnabled ? 'home' : 'dashboard';
|
||||
const target = needsOnboarding ? 'onboarding' : landingTarget;
|
||||
return next(frontendURL(`accounts/${routeAccountId}/${target}`));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user