Skip to content

Commit 133de22

Browse files
refactor(NotificationsMenuComponent): Convert to standalone (#2022)
1 parent 346b33a commit 133de22

File tree

7 files changed

+113
-98
lines changed

7 files changed

+113
-98
lines changed

src/app/teacher/classroom-monitor.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ import { GradingNodeService } from '../../assets/wise5/services/gradingNodeServi
4545
NodeProgressViewComponent,
4646
NotebookGradingComponent,
4747
NotebookWorkgroupGradingComponent,
48-
NotificationsMenuComponent,
4948
StepItemComponent,
5049
StudentGradingComponent,
5150
StudentGradingToolsComponent,
@@ -64,6 +63,7 @@ import { GradingNodeService } from '../../assets/wise5/services/gradingNodeServi
6463
ManageStudentsModule,
6564
MilestoneModule,
6665
NavItemScoreComponent,
66+
NotificationsMenuComponent,
6767
PauseScreensMenuComponent,
6868
PeerGroupGradingModule,
6969
PreviewComponentComponent,

src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/notifications-menu/notifications-menu.component.html

Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,57 @@
99
 
1010
<span i18n>Alerts</span>
1111
</span>
12-
<button
13-
mat-icon-button
14-
*ngIf="newNotifications.length > 0"
15-
(click)="confirmDismissAllNotifications()"
16-
[disabled]="newNotifications.length === 0"
17-
matTooltip="Clear all notifications"
18-
matTooltipPosition="left"
19-
i18n-matTooltip
20-
aria-label="Clear all notifications"
21-
i18n-aria-label
22-
>
23-
<mat-icon>clear_all</mat-icon>
24-
</button>
12+
@if (newNotifications.length > 0) {
13+
<button
14+
mat-icon-button
15+
(click)="confirmDismissAllNotifications()"
16+
[disabled]="newNotifications.length === 0"
17+
matTooltip="Clear all notifications"
18+
matTooltipPosition="left"
19+
i18n-matTooltip
20+
>
21+
<mat-icon>clear_all</mat-icon>
22+
</button>
23+
}
2524
</mat-toolbar>
2625
<div class="account-menu__actions notifications-content" fxFlex>
27-
<p class="no-notifications" *ngIf="newNotifications.length === 0" i18n>You have no new alerts at this time.</p>
28-
<mat-list *ngIf="newNotifications.length > 0">
29-
<ng-container *ngFor="let notification of newNotifications; let last = last">
30-
<mat-list-item>
31-
<div fxLayout="row" fxLayoutAlign="start center">
32-
<div class="notification-content">
33-
<div>
34-
<a
35-
(click)="visitNode(notification)"
36-
tabindex="0"
37-
matTooltip="Go to {{ getNodePositionAndTitle(notification.nodeId) }}"
38-
matTooltipPosition="left"
39-
i18n-matTooltip
40-
>{{ notification.message }}</a
41-
>
26+
@if (newNotifications.length === 0) {
27+
<p class="no-notifications" i18n>You have no new alerts at this time.</p>
28+
} @else {
29+
<mat-list>
30+
@for (notification of newNotifications; track notification.id) {
31+
<mat-list-item>
32+
<div fxLayout="row" fxLayoutAlign="start center">
33+
<div class="notification-content">
34+
<div>
35+
<a
36+
(click)="visitNode(notification)"
37+
tabindex="0"
38+
matTooltip="Go to {{ getNodePositionAndTitle(notification.nodeId) }}"
39+
matTooltipPosition="left"
40+
i18n-matTooltip
41+
>{{ notification.message }}</a
42+
>
43+
</div>
44+
<div class="secondary-text mat-body-2">
45+
{{ getNodePositionAndTitle(notification.nodeId) }}
46+
</div>
4247
</div>
43-
<div class="secondary-text mat-body-2">{{ getNodePositionAndTitle(notification.nodeId) }}</div>
48+
<span fxFlex></span>
49+
<button
50+
mat-icon-button
51+
(click)="dismissNotification(notification)"
52+
fxLayoutAlign="center center"
53+
aria-label="Clear"
54+
i18n-aria-label
55+
>
56+
<mat-icon>clear</mat-icon>
57+
</button>
4458
</div>
45-
<span fxFlex></span>
46-
<button
47-
mat-icon-button
48-
(click)="dismissNotification(notification)"
49-
fxLayoutAlign="center center"
50-
aria-label="Clear"
51-
i18n-aria-label
52-
>
53-
<mat-icon>clear</mat-icon>
54-
</button>
55-
</div>
56-
</mat-list-item>
57-
<mat-divider></mat-divider>
58-
</ng-container>
59-
</mat-list>
59+
</mat-list-item>
60+
<mat-divider />
61+
}
62+
</mat-list>
63+
}
6064
</div>
6165
</div>
Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,39 @@
11
import { provideHttpClientTesting } from '@angular/common/http/testing';
22
import { ComponentFixture, TestBed } from '@angular/core/testing';
3-
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
4-
import { MatIconModule } from '@angular/material/icon';
5-
import { MatToolbarModule } from '@angular/material/toolbar';
3+
import { MatDialog } from '@angular/material/dialog';
64
import { of } from 'rxjs';
75
import { Notification } from '../../../../../../app/domain/notification';
86
import { DialogWithConfirmComponent } from '../../../../directives/dialog-with-confirm/dialog-with-confirm.component';
97
import { NotificationService } from '../../../../services/notificationService';
108
import { ClassroomMonitorTestingModule } from '../../../classroom-monitor-testing.module';
119
import { NotificationsMenuComponent } from './notifications-menu.component';
12-
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
10+
import { provideRouter } from '@angular/router';
1311

1412
let component: NotificationsMenuComponent;
1513
let dismissNotificationSpy: jasmine.Spy;
1614
let fixture: ComponentFixture<NotificationsMenuComponent>;
1715
const NODE_ID_1: string = 'node1';
1816
const NODE_ID_2: string = 'node1';
19-
const NODE_ROUTE = 'root.cm.unit.node';
2017
const notification1 = new Notification({ nodeId: NODE_ID_1 });
2118
const notification2 = new Notification({ nodeId: NODE_ID_2 });
22-
let stateGoSpy: jasmine.Spy;
23-
2419
describe('NotificationsMenuComponent', () => {
2520
beforeEach(async () => {
2621
await TestBed.configureTestingModule({
27-
declarations: [DialogWithConfirmComponent, NotificationsMenuComponent],
28-
imports: [ClassroomMonitorTestingModule,
29-
MatDialogModule,
30-
MatIconModule,
31-
MatToolbarModule],
32-
providers: [{ provide: MatDialog, useValue: { open: () => { } } }, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()]
33-
}).compileComponents();
22+
declarations: [DialogWithConfirmComponent],
23+
imports: [ClassroomMonitorTestingModule, NotificationsMenuComponent],
24+
providers: [
25+
{ provide: MatDialog, useValue: { open: () => {} } },
26+
provideHttpClientTesting(),
27+
provideRouter([])
28+
]
29+
}).compileComponents();
3430
});
3531

3632
beforeEach(() => {
3733
fixture = TestBed.createComponent(NotificationsMenuComponent);
3834
component = fixture.componentInstance;
3935
component.state = { go: () => {} };
4036
dismissNotificationSpy = spyOn(TestBed.inject(NotificationService), 'dismissNotification');
41-
stateGoSpy = spyOn(component.state, 'go');
4237
fixture.detectChanges();
4338
});
4439

@@ -57,7 +52,7 @@ function confirmDismissAllNotifications() {
5752
}
5853
} as any);
5954
component.newNotifications = [notification1, notification2];
60-
component.confirmDismissAllNotifications();
55+
component['confirmDismissAllNotifications']();
6156
expect(dialogOpenSpy).toHaveBeenCalled();
6257
expect(dismissNotificationSpy).toHaveBeenCalledTimes(2);
6358
});
@@ -67,7 +62,7 @@ function confirmDismissAllNotifications() {
6762
function dismissNotification() {
6863
describe('dismissNotification', () => {
6964
it('should dismiss notification', () => {
70-
component.dismissNotification(notification1);
65+
component['dismissNotification'](notification1);
7166
expect(dismissNotificationSpy).toHaveBeenCalledWith(notification1);
7267
});
7368
});
@@ -76,8 +71,9 @@ function dismissNotification() {
7671
function visitNode() {
7772
describe('visitNode', () => {
7873
it('should visit node', () => {
79-
component.visitNode(notification1);
80-
expect(stateGoSpy).toHaveBeenCalledWith(NODE_ROUTE, { nodeId: NODE_ID_1 });
74+
const routerSpy = spyOn(component['router'], 'navigate');
75+
component['visitNode'](notification1);
76+
expect(routerSpy).toHaveBeenCalled();
8177
});
8278
});
8379
}
Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,53 @@
1-
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
1+
import { Component, Input, ViewEncapsulation } from '@angular/core';
22
import { MatDialog } from '@angular/material/dialog';
33
import { NotificationService } from '../../../../services/notificationService';
44
import { TeacherProjectService } from '../../../../services/teacherProjectService';
55
import { DialogWithConfirmComponent } from '../../../../../../assets/wise5/directives/dialog-with-confirm/dialog-with-confirm.component';
66
import { Notification } from '../../../../../../app/domain/notification';
7+
import { CommonModule } from '@angular/common';
8+
import { MatButtonModule } from '@angular/material/button';
9+
import { MatIconModule } from '@angular/material/icon';
10+
import { MatTooltipModule } from '@angular/material/tooltip';
11+
import { MatToolbarModule } from '@angular/material/toolbar';
12+
import { MatListModule } from '@angular/material/list';
13+
import { MatDividerModule } from '@angular/material/divider';
14+
import { FlexLayoutModule } from '@angular/flex-layout';
15+
import { ActivatedRoute, Router } from '@angular/router';
716

817
@Component({
18+
encapsulation: ViewEncapsulation.None,
19+
imports: [
20+
CommonModule,
21+
FlexLayoutModule,
22+
MatButtonModule,
23+
MatDividerModule,
24+
MatIconModule,
25+
MatListModule,
26+
MatToolbarModule,
27+
MatTooltipModule
28+
],
929
selector: 'notifications-menu',
10-
templateUrl: './notifications-menu.component.html',
11-
styleUrls: ['./notifications-menu.component.scss'],
12-
encapsulation: ViewEncapsulation.None
30+
standalone: true,
31+
styleUrl: './notifications-menu.component.scss',
32+
templateUrl: './notifications-menu.component.html'
1333
})
14-
export class NotificationsMenuComponent implements OnInit {
34+
export class NotificationsMenuComponent {
1535
@Input() newNotifications: Notification[] = [];
1636
@Input() state: any;
17-
@Input() withPause: boolean;
1837

1938
constructor(
2039
private dialog: MatDialog,
2140
private notificationService: NotificationService,
22-
private projectService: TeacherProjectService
41+
private projectService: TeacherProjectService,
42+
private route: ActivatedRoute,
43+
private router: Router
2344
) {}
2445

25-
ngOnInit(): void {}
26-
27-
getNodePositionAndTitle(nodeId: string): string {
46+
protected getNodePositionAndTitle(nodeId: string): string {
2847
return this.projectService.getNodePositionAndTitle(nodeId);
2948
}
3049

31-
confirmDismissAllNotifications(): void {
50+
protected confirmDismissAllNotifications(): void {
3251
this.dialog
3352
.open(DialogWithConfirmComponent, {
3453
data: {
@@ -50,11 +69,13 @@ export class NotificationsMenuComponent implements OnInit {
5069
});
5170
}
5271

53-
dismissNotification(notification: Notification): void {
72+
protected dismissNotification(notification: Notification): void {
5473
this.notificationService.dismissNotification(notification);
5574
}
5675

57-
visitNode(notification: Notification): void {
58-
this.state.go('root.cm.unit.node', { nodeId: notification.nodeId });
76+
protected visitNode(notification: Notification): void {
77+
this.router.navigate(['node', notification.nodeId], {
78+
relativeTo: this.route
79+
});
5980
}
6081
}

src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/top-bar/top-bar.component.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,7 @@ <h3 fxLayout="row" fxLayoutAlign="start center" class="title-header">
5353
<mat-icon mat-menu-origin>notifications</mat-icon>
5454
</button>
5555
<mat-menu #notificationsMenu class="account-menu account-menu--fixed-width">
56-
<notifications-menu
57-
(click)="$event.stopPropagation()"
58-
[newNotifications]="newNotifications"
59-
[withPause]="true"
60-
>
61-
</notifications-menu>
56+
<notifications-menu (click)="$event.stopPropagation()" [newNotifications]="newNotifications" />
6257
</mat-menu>
6358
<button
6459
mat-icon-button

src/assets/wise5/classroomMonitor/classroomMonitorComponents/shared/top-bar/top-bar.component.spec.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,26 @@ import { ClassroomMonitorTestingModule } from '../../../classroom-monitor-testin
1010
import { PauseScreensMenuComponent } from '../../pause-screens-menu/pause-screens-menu.component';
1111
import { NotificationsMenuComponent } from '../notifications-menu/notifications-menu.component';
1212
import { TopBarComponent } from './top-bar.component';
13+
import { provideRouter } from '@angular/router';
1314

1415
describe('TopBarComponent', () => {
1516
let component: TopBarComponent;
1617
let fixture: ComponentFixture<TopBarComponent>;
1718

1819
beforeEach(async () => {
1920
await TestBed.configureTestingModule({
20-
declarations: [NotificationsMenuComponent, TopBarComponent],
21+
declarations: [TopBarComponent],
2122
imports: [
2223
ClassroomMonitorTestingModule,
24+
NotificationsMenuComponent,
2325
PauseScreensMenuComponent,
2426
MatIconModule,
2527
MatListModule,
2628
MatMenuModule,
2729
MatToolbarModule,
2830
MatTooltipModule
29-
]
31+
],
32+
providers: [provideRouter([])]
3033
}).compileComponents();
3134
});
3235

0 commit comments

Comments
 (0)