Skip to content

Commit 6ab8d36

Browse files
committed
MOBILE-4910 mainmenu: Show custom menu items on user menu
1 parent 3214af8 commit 6ab8d36

File tree

7 files changed

+186
-28
lines changed

7 files changed

+186
-28
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
@if (type() !== 'embedded') {
2+
<ion-item button [href]="url()" [attr.aria-label]="label()" core-link [capture]="type() === 'app'"
3+
[inApp]="type() === 'inappbrowser'" class="core-custom-menu-item" [detail]="true"
4+
[detailIcon]="type() === 'browser' ? 'open-outline' : 'chevron-forward'">
5+
<ion-icon [name]="icon()" slot="start" aria-hidden="true" />
6+
<ion-label>
7+
<p class="item-heading">{{label()}}</p>
8+
</ion-label>
9+
</ion-item>
10+
} @else {
11+
<ion-item button (click)="openItem()" [attr.aria-label]="label()" class="core-custom-menu-item" [detail]="true">
12+
<ion-icon [name]="icon()" slot="start" aria-hidden="true" />
13+
<ion-label>
14+
<p class="item-heading">{{label()}}</p>
15+
</ion-label>
16+
</ion-item>
17+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import { CoreLinkOpenMethod } from '@/core/constants';
16+
import { CoreSharedModule } from '@/core/shared.module';
17+
import { Component, input } from '@angular/core';
18+
import { CoreViewer } from '@features/viewer/services/viewer';
19+
20+
/**
21+
* Component to display a custom menu item.
22+
*/
23+
@Component({
24+
selector: 'core-custom-menu-item',
25+
templateUrl: 'custom-menu-item.html',
26+
imports: [
27+
CoreSharedModule,
28+
],
29+
})
30+
export class CoreCustomMenuItemComponent {
31+
32+
/**
33+
* Type of the item: app, inappbrowser, browser or embedded.
34+
*/
35+
readonly type = input.required<CoreLinkOpenMethod>();
36+
37+
/**
38+
* Url of the item.
39+
*/
40+
readonly url = input.required<string>();
41+
42+
/**
43+
* Label to display for the item.
44+
*/
45+
readonly label = input.required<string>();
46+
47+
/**
48+
* Name of the icon to display for the item.
49+
*/
50+
readonly icon = input.required<string>();
51+
52+
/**
53+
* Open an embedded custom item.
54+
*/
55+
openItem(): void {
56+
CoreViewer.openIframeViewer(this.label(), this.url());
57+
}
58+
59+
}

src/core/features/mainmenu/components/user-menu/user-menu.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ <h1>
5050
<ng-container *ngTemplateOutlet="menuHandler; context: { handler, class: 'core-user-menu-handler', addSeparator: false }" />
5151
}
5252

53+
@for (item of customItems; track item) {
54+
<core-custom-menu-item [type]="item.type" [label]="item.label" [icon]="item.icon" [url]="item.url" />
55+
}
56+
5357
@for (handler of accountHandlers; track handler.name; let first = $first) {
5458
<ng-container
5559
*ngTemplateOutlet="menuHandler; context: { handler, class: 'core-user-account-menu-handler', addSeparator: first }" />

src/core/features/mainmenu/components/user-menu/user-menu.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import { CoreAlerts } from '@services/overlays/alerts';
3838
import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-component';
3939
import { CorePromiseUtils } from '@singletons/promise-utils';
4040
import type { ReloadableComponent } from '@coretypes/reloadable-component';
41+
import { CoreCustomMenu, CoreCustomMenuItem } from '@features/mainmenu/services/custommenu';
42+
import { CoreCustomMenuItemComponent } from '../custom-menu-item/custom-menu-item';
4143

4244
/**
4345
* Component to display a user menu.
@@ -49,6 +51,7 @@ import type { ReloadableComponent } from '@coretypes/reloadable-component';
4951
imports: [
5052
CoreSharedModule,
5153
CoreSiteLogoComponent,
54+
CoreCustomMenuItemComponent,
5255
],
5356
})
5457
export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
@@ -59,6 +62,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
5962
siteUrl?: string;
6063
displaySiteUrl = false;
6164
handlers: HandlerData[] = [];
65+
customItems?: CoreCustomMenuItem[];
6266
accountHandlers: HandlerData[] = [];
6367
handlersLoaded = false;
6468
user?: CoreUserProfile;
@@ -84,6 +88,8 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
8488
this.removeAccountOnLogout = !!CoreConstants.CONFIG.removeaccountonlogout;
8589
this.displaySiteUrl = currentSite.shouldDisplayInformativeLinks();
8690

91+
await this.loadCustomMenuItems();
92+
8793
await this.loadData();
8894
}
8995

@@ -177,6 +183,13 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
177183
event?.complete();
178184
}
179185

186+
/**
187+
* Load custom menu items.
188+
*/
189+
protected async loadCustomMenuItems(): Promise<void> {
190+
this.customItems = await CoreCustomMenu.getUserCustomMenuItems();
191+
}
192+
180193
/**
181194
* Opens User profile page.
182195
*

src/core/features/mainmenu/pages/more/more.html

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,25 +52,11 @@ <h1>{{ 'core.more' | translate }}</h1>
5252
</ion-item>
5353
}
5454
}
55-
<ng-container *ngFor="let item of customItems">
56-
@if (item.type !== 'embedded') {
57-
<ion-item button [href]="item.url" [attr.aria-label]="item.label" core-link [capture]="item.type === 'app'"
58-
[inApp]="item.type === 'inappbrowser'" class="core-moremenu-customitem" [detail]="true"
59-
[detailIcon]="item.type === 'browser' ? 'open-outline' : 'chevron-forward'">
60-
<ion-icon [name]="item.icon" slot="start" aria-hidden="true" />
61-
<ion-label>
62-
<p class="item-heading">{{item.label}}</p>
63-
</ion-label>
64-
</ion-item>
65-
} @else {
66-
<ion-item button (click)="openItem(item)" [attr.aria-label]="item.label" class="core-moremenu-customitem" [detail]="true">
67-
<ion-icon [name]="item.icon" slot="start" aria-hidden="true" />
68-
<ion-label>
69-
<p class="item-heading">{{item.label}}</p>
70-
</ion-label>
71-
</ion-item>
72-
}
73-
</ng-container>
55+
56+
@for (item of customItems; track item) {
57+
<core-custom-menu-item [type]="item.type" [label]="item.label" [icon]="item.icon" [url]="item.url" />
58+
}
59+
7460
@if (showScanQR) {
7561
<ion-item button (click)="scanQR()" [detail]="true">
7662
<ion-icon name="fas-qrcode" slot="start" aria-hidden="true" />

src/core/features/mainmenu/pages/more/more.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { CoreDynamicComponent } from '@components/dynamic-component/dynamic-comp
3636
import { ReloadableComponent } from '@coretypes/reloadable-component';
3737
import { CorePromiseUtils } from '@singletons/promise-utils';
3838
import { CoreCustomMenu, CoreCustomMenuItem } from '@features/mainmenu/services/custommenu';
39+
import { CoreCustomMenuItemComponent } from '@features/mainmenu/components/custom-menu-item/custom-menu-item';
3940

4041
/**
4142
* Page that displays the more page of the app.
@@ -47,6 +48,7 @@ import { CoreCustomMenu, CoreCustomMenuItem } from '@features/mainmenu/services/
4748
imports: [
4849
CoreSharedModule,
4950
CoreMainMenuUserButtonComponent,
51+
CoreCustomMenuItemComponent,
5052
],
5153
})
5254
export default class CoreMainMenuMorePage implements OnInit, OnDestroy {
@@ -143,15 +145,6 @@ export default class CoreMainMenuMorePage implements OnInit, OnDestroy {
143145
CoreNavigator.navigateToSitePath(handler.page, { params });
144146
}
145147

146-
/**
147-
* Open an embedded custom item.
148-
*
149-
* @param item Item to open.
150-
*/
151-
openItem(item: CoreCustomMenuItem): void {
152-
CoreViewer.openIframeViewer(item.label, item.url);
153-
}
154-
155148
/**
156149
* Open settings.
157150
*/
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
@app_parallel_run_core @core_mainmenu @app @javascript @custom_menu_items
2+
Feature: Custom user menu items display
3+
In order to access custom links in the user menu
4+
As a user
5+
I need to be able to see and interact with custom menu items
6+
7+
Background:
8+
Given the Moodle site is compatible with this feature
9+
And the following "users" exist:
10+
| username | firstname | lastname | email |
11+
| student | Student | User | student@moodle.com |
12+
13+
@lms_from5.2
14+
Scenario: Display custom user menu items with different types
15+
Given I log in as "admin"
16+
When I navigate to "General > Mobile app > Mobile features" in site administration
17+
And I set the field "Custom user menu items" to multiline:
18+
"""
19+
App item only English|https://www.moodle.org|inappbrowser|en_only
20+
Browser item|https://www.website2.org|browser|en
21+
Item de navegador|https://www.website2.org|browser|es
22+
Embedded item|https://www.moodle.org|embedded
23+
"""
24+
And I press "Save changes"
25+
And I entered the app as "student"
26+
When I press the user menu button in the app
27+
Then I should find "App item only English" in the app
28+
And I should find "Browser item" in the app
29+
And I should find "Embedded item" in the app
30+
And I should not find "Item de navegador" in the app
31+
32+
When I press "Browser item" in the app
33+
Then I should find "You are about to leave the app" in the app
34+
And I should find "https://www.website2.org" in the app
35+
36+
When I press "Cancel" in the app
37+
And I press "App item only English" in the app
38+
Then the app should have opened a browser tab with url "moodle.org"
39+
And I close the browser tab opened by the app
40+
41+
When I press "Embedded item" in the app
42+
Then the header should be "Embedded item" in the app
43+
44+
When I change language to "es" in the app
45+
And I press the user menu button in the app
46+
Then I should not find "App item only English" in the app
47+
And I should not find "Browser item" in the app
48+
And I should find "Embedded item" in the app
49+
And I should find "Item de navegador" in the app
50+
51+
Scenario: Display custom menu items with different types
52+
Given I log in as "admin"
53+
When I navigate to "General > Mobile app > Mobile features" in site administration
54+
And I set the field "Custom menu items" to multiline:
55+
"""
56+
App item only English|https://www.moodle.org|inappbrowser|en_only
57+
Browser item|https://www.website2.org|browser|en
58+
Item de navegador|https://www.website2.org|browser|es
59+
Embedded item|https://www.moodle.org|embedded
60+
"""
61+
And I press "Save changes"
62+
And I entered the app as "student"
63+
When I press the more menu button in the app
64+
Then I should find "App item only English" in the app
65+
And I should find "Browser item" in the app
66+
And I should find "Embedded item" in the app
67+
And I should not find "Item de navegador" in the app
68+
69+
When I press "Browser item" in the app
70+
Then I should find "You are about to leave the app" in the app
71+
And I should find "https://www.website2.org" in the app
72+
73+
When I press "Cancel" in the app
74+
And I press "App item only English" in the app
75+
Then the app should have opened a browser tab with url "moodle.org"
76+
And I close the browser tab opened by the app
77+
78+
When I press "Embedded item" in the app
79+
Then the header should be "Embedded item" in the app
80+
81+
When I change language to "es" in the app
82+
And I press the more menu button in the app
83+
Then I should not find "App item only English" in the app
84+
And I should not find "Browser item" in the app
85+
And I should find "Embedded item" in the app
86+
And I should find "Item de navegador" in the app

0 commit comments

Comments
 (0)