fix: Update route permissions in the new primary menu (#3499)

* fix: Display rolewise primary sidebar

* Fix issues with roles

* Fix active style

* Fix accessible menu

* Fix key missing

* Changes menu icon size

Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com>
This commit is contained in:
Pranav Raj S
2021-12-01 21:32:43 -08:00
committed by GitHub
parent b826319776
commit 8b4134c790
23 changed files with 282 additions and 349 deletions

View File

@@ -1,41 +1,37 @@
<template>
<aside class="woot-sidebar" :class="{ 'only-primary': !showSecondaryMenu }">
<aside class="woot-sidebar">
<primary-sidebar
:logo-source="globalConfig.logo"
:installation-name="globalConfig.installationName"
:account-id="accountId"
:menu-items="primaryMenuItems"
:active-menu-item="activePrimaryMenu.key"
@toggle-accounts="toggleAccountModal"
@key-shortcut-modal="toggleKeyShortcutModal"
/>
<secondary-sidebar
v-if="showSecondaryMenu"
:account-id="accountId"
:inboxes="inboxes"
:account-labels="accountLabels"
:labels="labels"
:teams="teams"
:menu-items="primaryMenuItems"
:menu-config="activeSecondaryMenu"
:current-role="currentRole"
@add-label="showAddLabelPopup"
/>
<woot-key-shortcut-modal
v-if="showShortcutModal"
@close="closeKeyShortcutModal"
@clickaway="closeKeyShortcutModal"
/>
<account-selector
:show-account-modal="showAccountModal"
@close-account-modal="toggleAccountModal"
@show-create-account-modal="openCreateAccountModal"
/>
<add-account-modal
:show="showCreateAccountModal"
@close-account-create-modal="closeCreateAccountModal"
/>
<woot-modal :show.sync="showAddLabelModal" :on-close="hideAddLabelPopup">
<add-label-modal @close="hideAddLabelPopup" />
</woot-modal>
@@ -46,14 +42,14 @@
import { mapGetters } from 'vuex';
import adminMixin from '../../mixins/isAdmin';
import { getSidebarItems } from '../../i18n/default-sidebar';
import { getSidebarItems } from './config/default-sidebar';
import alertMixin from 'shared/mixins/alertMixin';
import AccountSelector from './sidebarComponents/AccountSelector.vue';
import AddAccountModal from './sidebarComponents/AddAccountModal.vue';
import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel';
import PrimarySidebar from 'dashboard/modules/sidebar/components/Primary';
import SecondarySidebar from 'dashboard/modules/sidebar/components/Secondary';
import PrimarySidebar from './sidebarComponents/Primary';
import SecondarySidebar from './sidebarComponents/Secondary';
import WootKeyShortcutModal from 'components/widgets/modal/WootKeyShortcutModal';
import {
hasPressedAltAndCKey,
@@ -93,38 +89,34 @@ export default {
inboxes: 'inboxes/getInboxes',
accountId: 'getCurrentAccountId',
currentRole: 'getCurrentRole',
accountLabels: 'labels/getLabelsOnSidebar',
labels: 'labels/getLabelsOnSidebar',
teams: 'teams/getMyTeams',
}),
sideMenuItems() {
sideMenuConfig() {
return getSidebarItems(this.accountId);
},
primaryMenuItems() {
const menuItems = Object.values(
getSidebarItems(this.accountId).common.menuItems
const menuItems = this.sideMenuConfig.primaryMenu;
return menuItems.filter(menuItem =>
menuItem.roles.includes(this.currentRole)
);
},
activeSecondaryMenu() {
const { secondaryMenu } = this.sideMenuConfig;
const { name: currentRoute } = this.$route;
return menuItems;
const activeSecondaryMenu =
secondaryMenu.find(menuItem =>
menuItem.routes.includes(currentRoute)
) || {};
return activeSecondaryMenu;
},
currentRoute() {
return this.$store.state.route.name;
},
shouldShowNotificationsSideMenu() {
return this.sideMenuItems.notifications.routes.includes(
this.currentRoute
);
},
shouldShowProfileSideMenu() {
return (
this.currentRoute === 'profile_settings_index' ||
this.currentRoute === 'profile_settings'
);
},
showSecondaryMenu() {
if (this.shouldShowNotificationsSideMenu) return false;
if (this.shouldShowProfileSideMenu) return false;
return true;
activePrimaryMenu() {
const activePrimaryMenu =
this.primaryMenuItems.find(
menuItem => menuItem.key === this.activeSecondaryMenu.parentNav
) || {};
return activePrimaryMenu;
},
},
mounted() {
@@ -169,23 +161,11 @@ export default {
}
},
isCurrentRouteSameAsNavigation(routeName) {
return router.currentRoute && router.currentRoute.name === routeName;
return this.$route.name === routeName;
},
toggleSupportChatWindow() {
window.$chatwoot.toggle();
},
filterMenuItemsByRole(menuItems) {
if (!this.currentRole) {
return [];
}
return menuItems.filter(
menuItem =>
window.roleWiseRoutes[this.currentRole].indexOf(
menuItem.toStateName
) > -1
);
},
toggleAccountModal() {
this.showAccountModal = !this.showAccountModal;
},
@@ -208,12 +188,8 @@ export default {
<style lang="scss" scoped>
.woot-sidebar {
background: white;
background: var(--white);
display: flex;
&.only-primary {
width: auto;
}
}
.secondary-menu {

View File

@@ -0,0 +1,19 @@
import conversations from './sidebarItems/conversations';
import contacts from './sidebarItems/contacts';
import reports from './sidebarItems/reports';
import campaigns from './sidebarItems/campaigns';
import settings from './sidebarItems/settings';
import notifications from './sidebarItems/notifications';
import primaryMenu from './sidebarItems/primaryMenu';
export const getSidebarItems = accountId => ({
primaryMenu: primaryMenu(accountId),
secondaryMenu: [
conversations(accountId),
contacts(accountId),
reports(accountId),
campaigns(accountId),
settings(accountId),
notifications(accountId),
],
});

View File

@@ -0,0 +1,26 @@
import { frontendURL } from '../../../../helper/URLHelper';
const campaigns = accountId => ({
parentNav: 'campaigns',
routes: ['settings_account_campaigns', 'one_off'],
menuItems: [
{
icon: 'arrow-swap',
label: 'ONGOING',
key: 'ongoingCampaigns',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/campaigns/ongoing`),
toStateName: 'settings_account_campaigns',
},
{
key: 'oneOffCampaigns',
icon: 'sound-source',
label: 'ONE_OFF',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/campaigns/one_off`),
toStateName: 'one_off',
},
],
});
export default campaigns;

View File

@@ -0,0 +1,21 @@
import { frontendURL } from '../../../../helper/URLHelper';
const contacts = accountId => ({
parentNav: 'contacts',
routes: [
'contacts_dashboard',
'contact_profile_dashboard',
'contacts_labels_dashboard',
],
menuItems: [
{
icon: 'contact-card-group',
label: 'ALL_CONTACTS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/contacts`),
toStateName: 'contacts_dashboard',
},
],
});
export default contacts;

View File

@@ -0,0 +1,28 @@
import { frontendURL } from '../../../../helper/URLHelper';
const conversations = accountId => ({
parentNav: 'conversations',
routes: [
'home',
'inbox_dashboard',
'inbox_conversation',
'conversation_through_inbox',
'notifications_dashboard',
'label_conversations',
'conversations_through_label',
'team_conversations',
'conversations_through_team',
],
menuItems: [
{
icon: 'chat',
label: 'ALL_CONVERSATIONS',
key: 'conversations',
toState: frontendURL(`accounts/${accountId}/dashboard`),
toolTip: 'Conversation from all subscribed inboxes',
toStateName: 'home',
},
],
});
export default conversations;

View File

@@ -0,0 +1,7 @@
const notifications = () => ({
parentNav: 'notifications',
routes: ['notifications_index'],
menuItems: [],
});
export default notifications;

View File

@@ -0,0 +1,46 @@
import { frontendURL } from '../../../../helper/URLHelper';
const primaryMenuItems = accountId => [
{
icon: 'chat',
key: 'conversations',
label: 'CONVERSATIONS',
toState: frontendURL(`accounts/${accountId}/dashboard`),
toStateName: 'home',
roles: ['administrator', 'agent'],
},
{
icon: 'book-contacts',
key: 'contacts',
label: 'CONTACTS',
toState: frontendURL(`accounts/${accountId}/contacts`),
toStateName: 'contacts_dashboard',
roles: ['administrator', 'agent'],
},
{
icon: 'arrow-trending-lines',
key: 'reports',
label: 'REPORTS',
toState: frontendURL(`accounts/${accountId}/reports`),
toStateName: 'settings_account_reports',
roles: ['administrator'],
},
{
icon: 'megaphone',
key: 'campaigns',
label: 'CAMPAIGNS',
toState: frontendURL(`accounts/${accountId}/campaigns`),
toStateName: 'settings_account_campaigns',
roles: ['administrator'],
},
{
icon: 'settings',
key: 'settings',
label: 'SETTINGS',
toState: frontendURL(`accounts/${accountId}/settings`),
toStateName: 'settings_home',
roles: ['administrator', 'agent'],
},
];
export default primaryMenuItems;

View File

@@ -0,0 +1,7 @@
const profileSettings = () => ({
parentNav: 'profileSettings',
routes: ['profile_settings_index'],
menuItems: [],
});
export default profileSettings;

View File

@@ -0,0 +1,59 @@
import { frontendURL } from '../../../../helper/URLHelper';
const reports = accountId => ({
parentNav: 'reports',
routes: [
'settings_account_reports',
'csat_reports',
'agent_reports',
'label_reports',
'inbox_reports',
'team_reports',
],
menuItems: [
{
icon: 'arrow-trending-lines',
label: 'REPORTS_OVERVIEW',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports/overview`),
toStateName: 'settings_account_reports',
},
{
icon: 'emoji',
label: 'CSAT',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports/csat`),
toStateName: 'csat_reports',
},
{
icon: 'people',
label: 'REPORTS_AGENT',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports/agent`),
toStateName: 'agent_reports',
},
{
icon: 'tag',
label: 'REPORTS_LABEL',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports/label`),
toStateName: 'label_reports',
},
{
icon: 'mail-inbox-all',
label: 'REPORTS_INBOX',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports/inboxes`),
toStateName: 'inbox_reports',
},
{
icon: 'people-team',
label: 'REPORTS_TEAM',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/reports/teams`),
toStateName: 'team_reports',
},
],
});
export default reports;

View File

@@ -0,0 +1,112 @@
import { frontendURL } from '../../../../helper/URLHelper';
const settings = accountId => ({
parentNav: 'settings',
routes: [
'agent_list',
'canned_list',
'labels_list',
'settings_inbox',
'attributes_list',
'settings_inbox_new',
'settings_inbox_list',
'settings_inbox_show',
'settings_inboxes_page_channel',
'settings_inboxes_add_agents',
'settings_inbox_finish',
'settings_integrations',
'settings_integrations_webhook',
'settings_integrations_integration',
'settings_applications',
'settings_applications_webhook',
'settings_applications_integration',
'general_settings',
'general_settings_index',
'settings_teams_list',
'settings_teams_new',
'settings_teams_add_agents',
'settings_teams_finish',
'settings_teams_edit',
'settings_teams_edit_members',
'settings_teams_edit_finish',
'automation_list',
],
menuItems: [
{
icon: 'people',
label: 'AGENTS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/agents/list`),
toStateName: 'agent_list',
},
{
icon: 'people-team',
label: 'TEAMS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/teams/list`),
toStateName: 'settings_teams_list',
},
{
icon: 'mail-inbox-all',
label: 'INBOXES',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/inboxes/list`),
toStateName: 'settings_inbox_list',
},
{
icon: 'tag',
label: 'LABELS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/labels/list`),
toStateName: 'labels_list',
},
{
icon: 'code',
label: 'CUSTOM_ATTRIBUTES',
hasSubMenu: false,
toState: frontendURL(
`accounts/${accountId}/settings/custom-attributes/list`
),
toStateName: 'attributes_list',
},
{
icon: 'autocorrect',
label: 'AUTOMATION',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/automation/list`),
toStateName: 'automation_list',
},
{
icon: 'chat-multiple',
label: 'CANNED_RESPONSES',
hasSubMenu: false,
toState: frontendURL(
`accounts/${accountId}/settings/canned-response/list`
),
toStateName: 'canned_list',
},
{
icon: 'flash-on',
label: 'INTEGRATIONS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/integrations`),
toStateName: 'settings_integrations',
},
{
icon: 'star-emphasis',
label: 'APPLICATIONS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/applications`),
toStateName: 'settings_applications',
},
{
icon: 'settings',
label: 'ACCOUNT_SETTINGS',
hasSubMenu: false,
toState: frontendURL(`accounts/${accountId}/settings/general`),
toStateName: 'general_settings_index',
},
],
});
export default settings;

View File

@@ -0,0 +1,46 @@
<template>
<div class="logo">
<router-link :to="dashboardPath" replace>
<img :src="source" :alt="name" />
</router-link>
</div>
</template>
<script>
import { frontendURL } from 'dashboard/helper/URLHelper';
export default {
props: {
source: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
accountId: {
type: Number,
default: 0,
},
},
computed: {
dashboardPath() {
return frontendURL(`accounts/${this.accountId}/dashboard`);
},
},
};
</script>
<style lang="scss" scoped>
$logo-size: 32px;
.logo {
padding: var(--space-normal);
img {
width: $logo-size;
height: $logo-size;
object-fit: cover;
object-position: left center;
}
}
</style>

View File

@@ -10,7 +10,7 @@
</template>
<script>
import { mapGetters } from 'vuex';
import PrimaryNavItem from 'dashboard/modules/sidebar/components/PrimaryNavItem';
import PrimaryNavItem from './PrimaryNavItem';
export default {
components: { PrimaryNavItem },
@@ -21,7 +21,7 @@ export default {
}),
unreadCount() {
if (!this.notificationMetadata.unreadCount) {
return '0';
return '';
}
return this.notificationMetadata.unreadCount < 100

View File

@@ -25,7 +25,7 @@
variant="clear"
color-scheme="secondary"
size="small"
icon="ion-help-buoy"
icon="chat-help"
@click="$emit('show-support-chat-window')"
>
{{ $t('SIDEBAR_ITEMS.CONTACT_SUPPORT') }}

View File

@@ -0,0 +1,112 @@
<template>
<div class="primary--sidebar">
<logo
:source="logoSource"
:name="installationName"
:account-id="accountId"
/>
<nav class="menu vertical">
<primary-nav-item
v-for="menuItem in menuItems"
:key="menuItem.toState"
:icon="menuItem.icon"
:name="menuItem.label"
:to="menuItem.toState"
:is-child-menu-active="menuItem.key === activeMenuItem"
/>
</nav>
<div class="menu vertical user-menu">
<notification-bell />
<agent-details @toggle-menu="toggleOptions" />
<options-menu
:show="showOptionsMenu"
@toggle-accounts="toggleAccountModal"
@show-support-chat-window="toggleSupportChatWindow"
@key-shortcut-modal="$emit('key-shortcut-modal')"
@close="toggleOptions"
/>
</div>
</div>
</template>
<script>
import Logo from './Logo';
import PrimaryNavItem from './PrimaryNavItem';
import OptionsMenu from './OptionsMenu';
import AgentDetails from './AgentDetails';
import NotificationBell from './NotificationBell';
import { frontendURL } from 'dashboard/helper/URLHelper';
export default {
components: {
Logo,
PrimaryNavItem,
OptionsMenu,
AgentDetails,
NotificationBell,
},
props: {
logoSource: {
type: String,
default: '',
},
installationName: {
type: String,
default: '',
},
accountId: {
type: Number,
default: 0,
},
menuItems: {
type: Array,
default: () => [],
},
activeMenuItem: {
type: String,
default: '',
},
},
data() {
return {
showOptionsMenu: false,
};
},
methods: {
frontendURL,
toggleOptions() {
this.showOptionsMenu = !this.showOptionsMenu;
},
toggleAccountModal() {
this.$emit('toggle-accounts');
},
toggleSupportChatWindow() {
window.$chatwoot.toggle();
},
},
};
</script>
<style lang="scss" scoped>
.primary--sidebar {
display: flex;
flex-direction: column;
width: var(--space-jumbo);
border-right: 1px solid var(--s-50);
box-sizing: content-box;
height: 100vh;
flex-shrink: 0;
}
.menu {
align-items: center;
margin-top: var(--space-medium);
}
.user-menu {
display: flex;
flex-direction: column;
flex-grow: 1;
justify-content: flex-end;
margin-bottom: var(--space-normal);
}
</style>

View File

@@ -0,0 +1,78 @@
<template>
<router-link v-slot="{ href, isActive, navigate }" :to="to" custom>
<a
v-tooltip.right="$t(`SIDEBAR.${name}`)"
:href="href"
class="button clear button--only-icon menu-item"
:class="{ 'is-active': isActive || isChildMenuActive }"
@click="navigate"
>
<fluent-icon :icon="icon" />
<span class="show-for-sr">{{ name }}</span>
<span v-if="count" class="badge warning">{{ count }}</span>
</a>
</router-link>
</template>
<script>
export default {
props: {
to: {
type: String,
default: '',
},
name: {
type: String,
default: '',
},
icon: {
type: String,
default: '',
},
count: {
type: String,
default: '',
},
isChildMenuActive: {
type: Boolean,
default: false,
},
},
};
</script>
<style lang="scss" scoped>
.button {
margin: var(--space-small) 0;
}
.menu-item {
display: inline-flex;
position: relative;
border-radius: var(--border-radius-large);
border: 1px solid transparent;
color: var(--s-600);
&:hover {
background: var(--w-25);
color: var(--s-600);
}
&:focus {
border-color: var(--w-500);
}
&.is-active {
background: var(--w-50);
color: var(--w-500);
}
}
.icon {
font-size: var(--font-size-default);
}
.badge {
position: absolute;
right: var(--space-minus-smaller);
top: var(--space-minus-smaller);
}
</style>

View File

@@ -0,0 +1,167 @@
<template>
<div v-if="menuConfig.menuItems.length" class="main-nav secondary-menu">
<transition-group name="menu-list" tag="ul" class="menu vertical">
<secondary-nav-item
v-for="menuItem in accessibleMenuItems"
:key="menuItem.toState"
:menu-item="menuItem"
/>
<secondary-nav-item
v-for="menuItem in additionalSecondaryMenuItems[menuConfig.parentNav]"
:key="menuItem.key"
:menu-item="menuItem"
@add-label="showAddLabelPopup"
/>
</transition-group>
</div>
</template>
<script>
import { frontendURL } from '../../../helper/URLHelper';
import SecondaryNavItem from './SecondaryNavItem.vue';
export default {
components: {
SecondaryNavItem,
},
props: {
accountId: {
type: Number,
default: 0,
},
labels: {
type: Array,
default: () => [],
},
inboxes: {
type: Array,
default: () => [],
},
teams: {
type: Array,
default: () => [],
},
menuConfig: {
type: Object,
default: () => {},
},
currentRole: {
type: String,
default: '',
},
},
computed: {
accessibleMenuItems() {
if (!this.currentRole) {
return [];
}
return this.menuConfig.menuItems.filter(
menuItem =>
window.roleWiseRoutes[this.currentRole].indexOf(
menuItem.toStateName
) > -1
);
},
inboxSection() {
return {
icon: 'folder',
label: 'INBOXES',
hasSubMenu: true,
newLink: true,
newLinkTag: 'NEW_INBOX',
key: 'inbox',
toState: frontendURL(`accounts/${this.accountId}/settings/inboxes/new`),
toStateName: 'settings_inbox_new',
newLinkRouteName: 'settings_inbox_new',
children: this.inboxes.map(inbox => ({
id: inbox.id,
label: inbox.name,
truncateLabel: true,
toState: frontendURL(`accounts/${this.accountId}/inbox/${inbox.id}`),
type: inbox.channel_type,
phoneNumber: inbox.phone_number,
})),
};
},
labelSection() {
return {
icon: 'number-symbol',
label: 'LABELS',
hasSubMenu: true,
newLink: true,
newLinkTag: 'NEW_LABEL',
key: 'label',
toState: frontendURL(`accounts/${this.accountId}/settings/labels`),
toStateName: 'labels_list',
showModalForNewItem: true,
modalName: 'AddLabel',
children: this.labels.map(label => ({
id: label.id,
label: label.title,
color: label.color,
truncateLabel: true,
toState: frontendURL(
`accounts/${this.accountId}/label/${label.title}`
),
})),
};
},
contactLabelSection() {
return {
icon: 'number-symbol',
label: 'TAGGED_WITH',
hasSubMenu: true,
key: 'label',
newLink: true,
newLinkTag: 'NEW_LABEL',
toState: frontendURL(`accounts/${this.accountId}/settings/labels`),
toStateName: 'labels_list',
showModalForNewItem: true,
modalName: 'AddLabel',
children: this.labels.map(label => ({
id: label.id,
label: label.title,
color: label.color,
truncateLabel: true,
toState: frontendURL(
`accounts/${this.accountId}/labels/${label.title}/contacts`
),
})),
};
},
teamSection() {
return {
icon: 'people-team',
label: 'TEAMS',
hasSubMenu: true,
newLink: true,
newLinkTag: 'NEW_TEAM',
key: 'team',
toState: frontendURL(`accounts/${this.accountId}/settings/teams/new`),
toStateName: 'settings_teams_new',
newLinkRouteName: 'settings_teams_new',
children: this.teams.map(team => ({
id: team.id,
label: team.name,
truncateLabel: true,
toState: frontendURL(`accounts/${this.accountId}/team/${team.id}`),
})),
};
},
additionalSecondaryMenuItems() {
let conversationMenuItems = [this.inboxSection, this.labelSection];
if (this.teams.length) {
conversationMenuItems = [this.teamSection, ...conversationMenuItems];
}
return {
conversations: conversationMenuItems,
contacts: [this.contactLabelSection],
};
},
},
methods: {
showAddLabelPopup() {
this.$emit('add-label');
},
},
};
</script>

View File

@@ -0,0 +1,145 @@
<template>
<router-link
v-slot="{ href, isActive, navigate }"
:to="to"
custom
active-class="active"
>
<li :class="{ active: isActive }">
<a
:href="href"
class="button clear menu-item text-truncate"
:class="{ 'is-active': isActive, 'text-truncate': shouldTruncate }"
@click="navigate"
>
<span v-if="icon" class="badge--icon">
<fluent-icon class="inbox-icon" :icon="icon" size="12" />
</span>
<span
v-if="labelColor"
class="badge--label"
:style="{ backgroundColor: labelColor }"
/>
<span
:title="menuTitle"
class="menu-label button__content"
:class="{ 'text-truncate': shouldTruncate }"
>
{{ label }}
</span>
<span v-if="count" class="badge" :class="{ secondary: !isActive }">
{{ count }}
</span>
</a>
</li>
</router-link>
</template>
<script>
export default {
props: {
to: {
type: String,
default: '',
},
label: {
type: String,
default: '',
},
labelColor: {
type: String,
default: '',
},
shouldTruncate: {
type: Boolean,
default: false,
},
icon: {
type: String,
default: '',
},
count: {
type: String,
default: '',
},
},
computed: {
showIcon() {
return { 'text-truncate': this.shouldTruncate };
},
menuTitle() {
return this.shouldTruncate ? this.label : '';
},
},
};
</script>
<style lang="scss" scoped>
$badge-size: var(--space-normal);
$label-badge-size: var(--space-slab);
.button {
margin: var(--space-small) 0;
}
.menu-item {
display: inline-flex;
color: var(--s-600);
font-weight: var(--font-weight-medium);
width: 100%;
height: var(--space-medium);
padding: var(--space-smaller) var(--space-smaller);
margin: var(--space-smaller) 0;
text-align: left;
&:hover {
background: var(--s-25);
color: var(--s-600);
}
&:focus {
border-color: var(--w-300);
}
&.is-active {
background: var(--w-25);
color: var(--w-500);
border-color: var(--w-25);
}
}
.menu-label {
flex-grow: 1;
line-height: var(--space-two);
}
.inbox-icon {
font-size: var(--font-size-nano);
}
.badge--label,
.badge--icon {
display: inline-flex;
border-radius: var(--border-radius-small);
margin-right: var(--space-smaller);
background: var(--s-100);
}
.badge--icon {
align-items: center;
height: $badge-size;
justify-content: center;
min-width: $badge-size;
}
.badge--label {
height: $label-badge-size;
min-width: $label-badge-size;
margin-left: var(--space-smaller);
}
.badge.secondary {
min-width: unset;
background: var(--s-75);
color: var(--s-600);
font-weight: var(--font-weight-bold);
}
</style>

View File

@@ -1,16 +1,24 @@
<template>
<li :class="computedClass" class="sidebar-item">
<a
class="sub-menu-title"
:class="getMenuItemClass"
data-tooltip
aria-haspopup="true"
:title="menuItem.toolTip"
>
<li class="sidebar-item">
<span v-if="hasSubMenu" class="secondary-menu--title fs-small">
{{ $t(`SIDEBAR.${menuItem.label}`) }}
</a>
<ul v-if="menuItem.hasSubMenu" class="nested vertical menu">
<secondary-nav-item
</span>
<router-link
v-else
class="secondary-menu--title secondary-menu--link fs-small"
:class="computedClass"
:to="menuItem.toState"
>
<fluent-icon
:icon="menuItem.icon"
class="secondary-menu--icon"
size="14"
/>
{{ $t(`SIDEBAR.${menuItem.label}`) }}
</router-link>
<ul v-if="hasSubMenu" class="nested vertical menu">
<secondary-child-nav-item
v-for="child in menuItem.children"
:key="child.id"
:to="child.toState"
@@ -20,7 +28,7 @@
:icon="computedInboxClass(child)"
/>
<router-link
v-if="menuItem.newLink"
v-if="showItem(menuItem)"
v-slot="{ href, isActive, navigate }"
:to="menuItem.toState"
custom
@@ -46,13 +54,13 @@
<script>
import { mapGetters } from 'vuex';
import adminMixin from '../../mixins/isAdmin';
import adminMixin from '../../../mixins/isAdmin';
import { getInboxClassByType } from 'dashboard/helper/inbox';
import SecondaryNavItem from 'dashboard/modules/sidebar/components/SecondaryNavItem';
import SecondaryChildNavItem from './SecondaryChildNavItem';
export default {
components: { SecondaryNavItem },
components: { SecondaryChildNavItem },
mixins: [adminMixin],
props: {
menuItem: {
@@ -62,10 +70,8 @@ export default {
},
computed: {
...mapGetters({ activeInbox: 'getSelectedInbox' }),
getMenuItemClass() {
return this.menuItem.cssClass
? `side-menu ${this.menuItem.cssClass}`
: 'side-menu';
hasSubMenu() {
return !!this.menuItem.children;
},
computedClass() {
// If active Inbox is present
@@ -76,7 +82,7 @@ export default {
this.$store.state.route.name === 'inbox_conversation' &&
this.menuItem.toStateName === 'home'
) {
return 'active';
return 'is-active';
}
return ' ';
},
@@ -88,14 +94,6 @@ export default {
const classByType = getInboxClassByType(type, phoneNumber);
return classByType;
},
computedChildClass(child) {
if (!child.truncateLabel) return '';
return 'text-truncate';
},
computedChildTitle(child) {
if (!child.truncateLabel) return false;
return child.label;
},
newLinkClick(e, navigate) {
if (this.menuItem.newLinkRouteName) {
navigate(e);
@@ -114,17 +112,46 @@ export default {
</script>
<style lang="scss" scoped>
.sidebar-item {
margin: var(--space-small) 0;
margin: var(--space-smaller) 0 0;
}
.sub-menu-title {
display: flex;
justify-content: space-between;
padding: 0 var(--space-small);
margin-bottom: var(--space-smaller);
.secondary-menu--title {
color: var(--s-600);
display: flex;
font-weight: var(--font-weight-bold);
line-height: var(--space-two);
text-transform: uppercase;
margin: var(--space-small) 0;
padding: 0 var(--space-small);
}
.secondary-menu--link {
display: flex;
align-items: center;
margin: 0;
padding: var(--space-small);
font-weight: var(--font-weight-medium);
border-radius: var(--border-radius-normal);
&:hover {
background: var(--s-25);
color: var(--s-600);
}
&:focus {
border-color: var(--w-300);
}
&.router-link-exact-active,
&.is-active {
background: var(--w-25);
color: var(--w-500);
border-color: var(--w-25);
}
}
.secondary-menu--icon {
margin-right: var(--space-smaller);
min-width: var(--space-normal);
}
.sub-menu-link {