Skip to content

Commit 47bc1ec

Browse files
authored
Merge pull request #236 from CenterForOpenScience/feat/left-menu-updates
Feat/left menu updates
2 parents 378106f + 0ad5c72 commit 47bc1ec

File tree

36 files changed

+578
-434
lines changed

36 files changed

+578
-434
lines changed

src/app/app.routes.ts

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@ import { authGuard, redirectIfLoggedInGuard } from './core/guards';
88
import { MyProfileResourceFiltersOptionsState } from './features/my-profile/components/filters/store';
99
import { MyProfileResourceFiltersState } from './features/my-profile/components/my-profile-resource-filters/store';
1010
import { MyProfileState } from './features/my-profile/store';
11+
import { PreprintState } from './features/preprints/store/preprint';
12+
import { RegistriesState } from './features/registries/store';
13+
import { LicensesHandlers, ProjectsHandlers, ProvidersHandlers } from './features/registries/store/handlers';
14+
import { FilesHandlers } from './features/registries/store/handlers/files.handlers';
1115
import { ResourceFiltersOptionsState } from './features/search/components/filters/store';
1216
import { ResourceFiltersState } from './features/search/components/resource-filters/store';
1317
import { SearchState } from './features/search/store';
18+
import { LicensesService } from './shared/services';
1419

1520
export const routes: Routes = [
1621
{
@@ -60,12 +65,9 @@ export const routes: Routes = [
6065
data: { skipBreadcrumbs: true },
6166
},
6267
{
63-
path: 'collections',
64-
loadChildren: () => import('./features/collections/collections.routes').then((mod) => mod.collectionsRoutes),
65-
},
66-
{
67-
path: 'meetings',
68-
loadChildren: () => import('./features/meetings/meetings.routes').then((mod) => mod.meetingsRoutes),
68+
path: 'search',
69+
loadComponent: () => import('./features/search/search.component').then((mod) => mod.SearchComponent),
70+
providers: [provideStates([ResourceFiltersState, ResourceFiltersOptionsState, SearchState])],
6971
},
7072
{
7173
path: 'my-projects',
@@ -75,24 +77,53 @@ export const routes: Routes = [
7577
canActivate: [authGuard],
7678
},
7779
{
78-
path: 'my-projects/:id',
79-
loadChildren: () => import('./features/project/project.routes').then((mod) => mod.projectRoutes),
80-
providers: [provideStates([ProjectsState, BookmarksState])],
80+
path: 'my-registrations',
8181
canActivate: [authGuard],
82+
loadComponent: () => import('@osf/features/registries/pages').then((c) => c.MyRegistrationsComponent),
83+
providers: [
84+
provideStates([RegistriesState]),
85+
ProvidersHandlers,
86+
ProjectsHandlers,
87+
LicensesService,
88+
LicensesHandlers,
89+
FilesHandlers,
90+
],
8291
},
8392
{
84-
path: 'settings',
85-
loadChildren: () => import('./features/settings/settings.routes').then((mod) => mod.settingsRoutes),
93+
path: 'my-preprints',
94+
canActivate: [authGuard],
95+
loadComponent: () =>
96+
import('@osf/features/preprints/pages/my-preprints/my-preprints.component').then(
97+
(m) => m.MyPreprintsComponent
98+
),
99+
providers: [provideStates([PreprintState])],
100+
},
101+
{
102+
path: 'project/:id',
103+
loadChildren: () => import('./features/project/project.routes').then((mod) => mod.projectRoutes),
104+
providers: [provideStates([ProjectsState, BookmarksState])],
86105
canActivate: [authGuard],
87106
},
88107
{
89108
path: 'preprints',
90109
loadChildren: () => import('./features/preprints/preprints.routes').then((mod) => mod.preprintsRoutes),
91110
},
92111
{
93-
path: 'search',
94-
loadComponent: () => import('./features/search/search.component').then((mod) => mod.SearchComponent),
95-
providers: [provideStates([ResourceFiltersState, ResourceFiltersOptionsState, SearchState])],
112+
path: 'preprints/:providerId/:id',
113+
loadComponent: () =>
114+
import('@osf/features/preprints/pages/preprint-details/preprint-details.component').then(
115+
(c) => c.PreprintDetailsComponent
116+
),
117+
},
118+
{
119+
path: 'registries',
120+
loadChildren: () => import('./features/registries/registries.routes').then((mod) => mod.registriesRoutes),
121+
},
122+
{
123+
path: 'registries/:id',
124+
loadChildren: () => import('./features/registry/registry.routes').then((mod) => mod.registryRoutes),
125+
providers: [provideStates([BookmarksState])],
126+
canActivate: [authGuard],
96127
},
97128
{
98129
path: 'my-profile',
@@ -107,13 +138,16 @@ export const routes: Routes = [
107138
loadChildren: () => import('./features/institutions/institutions.routes').then((r) => r.routes),
108139
},
109140
{
110-
path: 'registries',
111-
loadChildren: () => import('./features/registries/registries.routes').then((mod) => mod.registriesRoutes),
141+
path: 'collections',
142+
loadChildren: () => import('./features/collections/collections.routes').then((mod) => mod.collectionsRoutes),
112143
},
113144
{
114-
path: 'registries/:id',
115-
loadChildren: () => import('./features/registry/registry.routes').then((mod) => mod.registryRoutes),
116-
providers: [provideStates([BookmarksState])],
145+
path: 'meetings',
146+
loadChildren: () => import('./features/meetings/meetings.routes').then((mod) => mod.meetingsRoutes),
147+
},
148+
{
149+
path: 'settings',
150+
loadChildren: () => import('./features/settings/settings.routes').then((mod) => mod.settingsRoutes),
117151
canActivate: [authGuard],
118152
},
119153
{
Lines changed: 17 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,26 @@
11
<nav class="nav-menu">
22
<p-panelMenu [model]="mainMenuItems()" [multiple]="false">
33
<ng-template #item let-item>
4-
@if (item.id !== 'registry-details') {
5-
<a
6-
[routerLink]="item.routerLink"
7-
routerLinkActive="active"
8-
[routerLinkActiveOptions]="item.routerLinkActiveOptions"
9-
class="nav-link flex align-items-center"
10-
(click)="goToLink(item)"
11-
>
12-
@if (item.icon) {
13-
<osf-icon [iconClass]="`nav-icon ${item.icon}`"></osf-icon>
14-
}
15-
16-
<span>{{ item.label | translate }}</span>
4+
<a
5+
[routerLink]="item.routerLink ? item.routerLink : null"
6+
routerLinkActive="active"
7+
[routerLinkActiveOptions]="item.routerLinkActiveOptions"
8+
class="nav-link flex align-items-center"
9+
(click)="goToLink(item)"
10+
>
11+
@if (item.icon) {
12+
<osf-icon [iconClass]="`nav-icon ${item.icon}`"></osf-icon>
13+
}
1714

18-
@if (item.items) {
19-
<osf-icon
20-
class="ml-auto pt-1"
21-
[iconClass]="item.expanded ? `fas fa-chevron-down fa-sm` : `fas fa-chevron-right fa-sm`"
22-
></osf-icon>
23-
}
24-
</a>
15+
<span>{{ item.label | translate }}</span>
2516

26-
@if (item.id === 'my-projects' && !isRegistryRoute() && isProjectRoute()) {
27-
<div class="ml-4">
28-
<p-panelMenu [model]="myProjectMenuItems" [multiple]="false">
29-
<ng-template #item let-item>
30-
<a
31-
[routerLink]="item.routerLink ? ['/my-projects', currentResourceId(), item.routerLink] : null"
32-
[routerLinkActive]="item.routerLink ? 'active' : ''"
33-
[routerLinkActiveOptions]="{ exact: true }"
34-
class="nav-link flex align-items-center"
35-
(click)="goToLink(item)"
36-
>
37-
@if (item.icon) {
38-
<osf-icon [iconClass]="`nav-icon ${item.icon}`"></osf-icon>
39-
}
40-
<span>{{ item.label | translate }}</span>
41-
@if (item.items) {
42-
<osf-icon
43-
class="ml-auto pt-1"
44-
[iconClass]="item.expanded ? `fas fa-chevron-down fa-sm` : `fas fa-chevron-right fa-sm`"
45-
></osf-icon>
46-
}
47-
</a>
48-
</ng-template>
49-
</p-panelMenu>
50-
</div>
17+
@if (hasVisibleChildren | wrapFn: item) {
18+
<osf-icon
19+
class="ml-auto pt-1"
20+
[iconClass]="item.expanded ? `fas fa-chevron-down fa-sm` : `fas fa-chevron-right fa-sm`"
21+
></osf-icon>
5122
}
52-
}
53-
@if (item.id === 'registry-details' && isRegistryRoute()) {
54-
<p-panelMenu [model]="registrationMenuItems()" [multiple]="false" class="border-none">
55-
<ng-template #item let-item>
56-
<a
57-
[routerLink]="item.routerLink"
58-
[routerLinkActive]="item.routerLink ? 'active' : ''"
59-
[queryParams]="item.queryParams"
60-
[routerLinkActiveOptions]="{ exact: true }"
61-
class="nav-link flex align-items-center"
62-
(click)="goToLink(item)"
63-
>
64-
@if (item.icon) {
65-
<osf-icon [iconClass]="`nav-icon ${item.icon}`"></osf-icon>
66-
}
67-
<span>{{ item.label | translate }}</span>
68-
@if (item.items) {
69-
<osf-icon
70-
class="ml-auto pt-1"
71-
[iconClass]="item.expanded ? `fas fa-chevron-down fa-sm` : `fas fa-chevron-right fa-sm`"
72-
></osf-icon>
73-
}
74-
</a>
75-
</ng-template>
76-
</p-panelMenu>
77-
}
23+
</a>
7824
</ng-template>
7925
</p-panelMenu>
8026
</nav>

src/app/core/components/nav-menu/nav-menu.component.ts

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ import { Component, computed, inject, output } from '@angular/core';
1111
import { toSignal } from '@angular/core/rxjs-interop';
1212
import { ActivatedRoute, NavigationEnd, Router, RouterLink, RouterLinkActive } from '@angular/router';
1313

14-
import { MENU_ITEMS, MODERATION_MENU_ITEM, PROJECT_MENU_ITEMS, REGISTRATION_MENU_ITEMS } from '@core/constants';
15-
import { filterMenuItems } from '@osf/core/helpers';
16-
import { ProviderSelectors } from '@osf/core/store/provider';
17-
import { UserSelectors } from '@osf/core/store/user';
14+
import { MENU_ITEMS } from '@core/constants';
15+
import { filterMenuItems, updateMenuItems } from '@osf/core/helpers';
16+
import { RouteContext } from '@osf/core/models';
1817
import { AuthSelectors } from '@osf/features/auth/store';
1918
import { IconComponent } from '@osf/shared/components';
19+
import { WrapFnPipe } from '@osf/shared/pipes';
2020

2121
@Component({
2222
selector: 'osf-nav-menu',
23-
imports: [RouterLinkActive, RouterLink, PanelMenuModule, TranslatePipe, IconComponent],
23+
imports: [RouterLinkActive, RouterLink, PanelMenuModule, TranslatePipe, IconComponent, WrapFnPipe],
2424
templateUrl: './nav-menu.component.html',
2525
styleUrl: './nav-menu.component.scss',
2626
})
@@ -32,47 +32,23 @@ export class NavMenuComponent {
3232

3333
private readonly isAuthenticated = select(AuthSelectors.isAuthenticated);
3434

35-
protected readonly myProjectMenuItems = PROJECT_MENU_ITEMS;
36-
protected readonly registrationMenuItems = computed(() => {
37-
const menu = [...REGISTRATION_MENU_ITEMS];
38-
if (this.isUserModerator()) {
39-
const menuItems = menu[0].items ?? [];
40-
if (!menuItems.some((item) => item.label === MODERATION_MENU_ITEM.label)) {
41-
menuItems.push(MODERATION_MENU_ITEM);
42-
}
43-
}
44-
const withRouterLinks = menu.map((section) => ({
45-
...section,
46-
items: section.items?.map((item) => {
47-
const isModerationPage = item.state && item.state['isModeration'];
48-
const routeId = isModerationPage ? this.provider()?.id : this.currentResourceId();
49-
return {
50-
...item,
51-
routerLink: item.routerLink ? ['/registries', routeId, item.routerLink] : null,
52-
queryParams: isModerationPage ? { resourceId: this.currentResourceId() } : {},
53-
};
54-
}),
55-
}));
56-
return withRouterLinks;
57-
});
58-
protected readonly isUserModerator = select(UserSelectors.isCurrentUserModerator);
59-
protected readonly provider = select(ProviderSelectors.getCurrentProvider);
60-
6135
protected readonly mainMenuItems = computed(() => {
6236
const isAuthenticated = this.isAuthenticated();
63-
const menuItems = filterMenuItems(MENU_ITEMS, isAuthenticated);
64-
65-
if (this.isRegistryRouteDetails()) {
66-
menuItems.map((menuItem) => {
67-
if (menuItem.id === 'registries') {
68-
menuItem.expanded = true;
69-
return menuItem;
70-
}
71-
return menuItem;
72-
});
73-
}
37+
const filtered = filterMenuItems(MENU_ITEMS, isAuthenticated);
38+
39+
const routeContext: RouteContext = {
40+
resourceId: this.currentResourceId(),
41+
providerId: this.currentProviderId(),
42+
isProject: this.isProjectRoute() && !this.isRegistryRoute() && !this.isPreprintRoute(),
43+
isRegistry: this.isRegistryRoute(),
44+
isPreprint: this.isPreprintRoute(),
45+
isCollections: this.isCollectionsRoute() || false,
46+
currentUrl: this.router.url,
47+
};
48+
49+
const items = updateMenuItems(filtered, routeContext);
7450

75-
return this.isCollectionsRoute() ? menuItems : menuItems.filter((item) => item.routerLink !== '/collections');
51+
return items;
7652
});
7753

7854
protected readonly currentRoute = toSignal(
@@ -86,25 +62,27 @@ export class NavMenuComponent {
8662
);
8763

8864
protected readonly currentResourceId = computed(() => this.currentRoute().resourceId);
65+
protected readonly currentProviderId = computed(() => this.currentRoute().providerId);
8966
protected readonly isProjectRoute = computed(() => !!this.currentResourceId());
9067
protected readonly isCollectionsRoute = computed(() => this.currentRoute().isCollectionsWithId);
9168
protected readonly isRegistryRoute = computed(() => this.currentRoute().isRegistryRoute);
92-
protected readonly isRegistryRouteDetails = computed(() => this.currentRoute().isRegistryRouteDetails);
69+
protected readonly isPreprintRoute = computed(() => this.currentRoute().isPreprintRoute);
9370

9471
private getRouteInfo() {
9572
const urlSegments = this.router.url.split('/').filter((segment) => segment);
9673
const resourceFromQueryParams = this.route.snapshot.queryParams['resourceId'];
9774
const resourceId = this.route.firstChild?.snapshot.params['id'] || resourceFromQueryParams;
98-
const section = this.route.firstChild?.firstChild?.snapshot.url[0]?.path || 'overview';
75+
const providerId = this.route.firstChild?.snapshot.params['providerId'];
9976
const isCollectionsWithId = urlSegments[0] === 'collections' && urlSegments[1] && urlSegments[1] !== '';
10077
const isRegistryRoute = urlSegments[0] === 'registries' && !!urlSegments[2];
101-
const isRegistryRouteDetails = urlSegments[0] === 'registries' && urlSegments[2] === 'overview';
78+
const isPreprintRoute = urlSegments[0] === 'preprints' && !!urlSegments[2];
79+
10280
return {
10381
resourceId,
104-
section,
82+
providerId,
10583
isCollectionsWithId,
10684
isRegistryRoute,
107-
isRegistryRouteDetails,
85+
isPreprintRoute,
10886
};
10987
}
11088

@@ -113,4 +91,7 @@ export class NavMenuComponent {
11391
this.closeMenu.emit();
11492
}
11593
}
94+
95+
protected readonly hasVisibleChildren = (item: MenuItem): boolean =>
96+
Array.isArray(item.items) && item.items.some((child) => !!child.visible);
11697
}

0 commit comments

Comments
 (0)