Skip to content

Commit

Permalink
Integrate views to the SideNav
Browse files Browse the repository at this point in the history
  • Loading branch information
jardakotesovec committed Sep 24, 2024
1 parent 128078a commit 0fdfdd0
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 143 deletions.
3 changes: 2 additions & 1 deletion src/components/SideMenu/SideMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
v-bind="itemProps.action"
:href="item.link || '#'"
tabindex="-1"
@click.prevent="() => {}"
>
<Badge
v-if="item.badge?.slot"
v-if="item.badge?.slot != null"
:color-variant="item.badge.colorVariant || 'primary'"
v-bind="item.badge"
class="me-1"
Expand Down
86 changes: 79 additions & 7 deletions src/components/SideNav/SideNav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
</template>

<script setup>
import {reactive, toRef, watchEffect} from 'vue';
import {ref, watch, computed} from 'vue';
import {useSideMenu} from '@/composables/useSideMenu.js';
import SideMenu from '../SideMenu/SideMenu.vue';
import {useUrl} from '@/composables/useUrl';
import {useFetch} from '@/composables/useFetch';
const props = defineProps({
/**
Expand All @@ -40,8 +42,78 @@ const props = defineProps({
});
let currentActiveKey = '';
const linksRef = toRef(props, 'links');
const items = reactive(convertLinksToArray(linksRef.value));
const menuItems = ref(convertLinksToArray(props.links));
/**
* Dashboards count
* */
const {apiUrl: dashboardCountUrl} = useUrl('_submissions/viewsCount');
const {data: dashboardCount, fetch: fetchDashboardCount} =
useFetch(dashboardCountUrl);
const dashboardsMenuItem = menuItems.value.find(
(item) => item.key === 'dashboards',
);
if (dashboardsMenuItem) {
fetchDashboardCount();
}
/**
* mySubmissions count
*/
const {apiUrl: mySubmissionsCountUrl} = useUrl('_submissions/viewsCount');
const {data: mySubmissionsCount, fetch: fetchMySubmissionsCount} = useFetch(
mySubmissionsCountUrl,
);
const mySubmissionsMenuItem = menuItems.value.find(
(item) => item.key === 'mySubmissions',
);
if (mySubmissionsMenuItem) {
fetchMySubmissionsCount();
}
/**
* reviewAssignments count
*/
const {apiUrl: reviewAssignmentCountUrl} = useUrl('_submissions/viewsCount');
const {data: reviewAssignmentCount, fetch: fetchReviewAssignmentCount} =
useFetch(reviewAssignmentCountUrl);
const reviewAssignmentMenuItem = menuItems.value.find(
(item) => item.key === 'reviewAssignments',
);
if (reviewAssignmentMenuItem) {
fetchReviewAssignmentCount();
}
// helper to attach count to the menu item
function enrichMenuItemWithCounts(page, itemsCount) {
if (itemsCount.value) {
const menuItem = menuItems.value.find((item) => item.key === page);
if (menuItem) {
const menuItemsEnriched = menuItem.items.map((item) => ({
...item,
badge: {
slot: itemsCount.value[item.id],
},
}));
menuItem.items = menuItemsEnriched;
}
}
}
const menuItemsEnriched = computed(() => {
enrichMenuItemWithCounts('dashboards', dashboardCount);
enrichMenuItemWithCounts('mySubmissions', mySubmissionsCount);
enrichMenuItemWithCounts('reviewAssignments', reviewAssignmentCount);
return menuItems.value;
});
function convertLinksToArray(links, level = 1, parentKey = '') {
const result = [];
Expand Down Expand Up @@ -99,12 +171,12 @@ function getExpandedKeys(items) {
return _expandedKeys;
}
const {sideMenuProps} = useSideMenu(items, {
const {sideMenuProps} = useSideMenu(menuItemsEnriched, {
activeItemKey: currentActiveKey,
expandedKeys: getExpandedKeys(items),
expandedKeys: getExpandedKeys(menuItems.value),
});
watchEffect(() => {
Object.assign(items, convertLinksToArray(linksRef.value));
watch(props.links, (newLinks) => {
menuItems.value = convertLinksToArray(newLinks);
});
</script>
7 changes: 7 additions & 0 deletions src/composables/useQueryParams.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {useUrlSearchParams} from '@vueuse/core';

const queryParams = useUrlSearchParams();

export function useQueryParams() {
return queryParams;
}
34 changes: 28 additions & 6 deletions src/composables/useSideMenu.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import {toRef, ref, computed} from 'vue';
import {useQueryParams} from '@/composables/useQueryParams';

export function useSideMenu(_items, opts = {}) {
const queryParams = useQueryParams();

const _activeItemKey = opts.activeItemKey || '';
const _expandedKeys = opts.expandedKeys || {};
const onActionFn = opts.onActionFn || (() => {});

const itemsRef = toRef(_items);

if (typeof itemsRef.value === 'undefined') {
throw new Error('items must be provided to use this api');
}

const items = computed(() => mapItems(itemsRef.value));
const items = computed(() => {
return mapItems(itemsRef.value);
});
const expandedKeys = ref(_expandedKeys);
const activeItemKey = ref(_activeItemKey);

Expand Down Expand Up @@ -53,11 +57,20 @@ export function useSideMenu(_items, opts = {}) {
activeItemKey.value = key;
}

function compareUrlPaths(url1, url2) {
const parsedUrl1 = new URL(url1);
const parsedUrl2 = new URL(url2);
return (
parsedUrl1.pathname === parsedUrl2.pathname &&
parsedUrl1.hostname === parsedUrl2.hostname
);
}

// Maps the level attributes which are necessary to render the nested menu
function mapItems(_items, level = 1) {
function mapItems(__items, level = 1) {
const result = [];

_items.forEach((_item, index) => {
__items.forEach((_item, index) => {
const item = {
..._item,
level,
Expand All @@ -70,7 +83,16 @@ export function useSideMenu(_items, opts = {}) {

if (item.link) {
item.command = () => {
window.location.href = item.link;
if (compareUrlPaths(window.location.href, item.link)) {
// only update query params, without reloading page, important for dashboards
const parsedUrl = new URL(item.link);
const params = new URLSearchParams(parsedUrl.search);
for (const [key, value] of params) {
queryParams[key] = value;
}
} else {
window.location.href = item.link;
}
setActiveItemKey(item.key);
};
}
Expand Down
17 changes: 3 additions & 14 deletions src/pages/dashboard/DashboardPage.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
<template>
<div class="me-3 flex min-h-screen gap-8 text-base-normal">
<div class="flex-none border-l border-r border-light">
<DashboardViews
:title="store.dashboardPageTitle"
:icon="store.dashboardPageIcon"
:dashboard-page="store.dashboardPage"
:views="store.views"
:current-view="store.currentView"
@load-view="store.loadView"
/>
</div>
<div class="flex-grow">
<div class="min-h-screentext-base-normal me-3 ms-5 text-base-normal">
<div class="">
<h2 class="flex items-center gap-4 py-6 text-5xl-bold">
{{
`${store.currentView.name} (${store.submissionsPagination.itemCount})`
Expand All @@ -23,7 +13,7 @@
</PkpButton>
<div>
<Search
:search-phrase="searchPhrase"
:search-phrase="store.searchPhrase"
:search-label="t('editor.submission.search')"
@search-phrase-changed="
(...args) => store.setSearchPhrase(...args)
Expand Down Expand Up @@ -56,7 +46,6 @@
import PkpButton from '@/components/Button/Button.vue';
import ActiveFilters from './components/ActiveFilters.vue';
import DashboardTable from './components/DashboardTable/DashboardTable.vue';
import DashboardViews from '@/pages/dashboard/components/DashboardViews.vue';
import Search from '@/components/Search/Search.vue';
import {useDashboardPageStore} from './dashboardPageStore';
Expand Down
61 changes: 0 additions & 61 deletions src/pages/dashboard/components/DashboardViews.vue

This file was deleted.

Loading

0 comments on commit 0fdfdd0

Please sign in to comment.