Skip to content

Commit 8ef55da

Browse files
committed
Overridden appshell,wssnavbar and banner to implement new material navigation bar
1 parent e8ca544 commit 8ef55da

File tree

11 files changed

+668
-20
lines changed

11 files changed

+668
-20
lines changed

sdk-mediaco-component-map.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
// Statically load all "MediaCo" components.
22

3-
import { AppShellComponent } from './src/app/_mediaco/overrides/app-shell/app-shell.component';
3+
import { AppShellComponent } from 'src/app/_samples/mediaco/overrides/app-shell/app-shell.component';
4+
import { BannerComponent } from 'src/app/_samples/mediaco/overrides/banner/banner.component';
5+
import { WssNavBarComponent } from 'src/app/_samples/mediaco/overrides/wss-nav-bar/wss-nav-bar.component';
6+
47
/* import end - DO NOT REMOVE */
58

69
// sdkMediaCoComponentMap is the JSON object where we'll store the components that are
710
// specific to MediaCo application.
811

912
const sdkMediaCoComponentMap = {
10-
AppShell: AppShellComponent
13+
AppShell: AppShellComponent,
14+
WssNavBar: WssNavBarComponent,
15+
Banner: BannerComponent
1116
/* map end - DO NOT REMOVE */
1217
};
1318

src/app/_samples/mediaco/overrides/app-shell/app-shell.component.html

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,9 @@
33
<component-mapper name="NavBar" [props]="{ pConn$, appName$, pages$, caseTypes$ }"></component-mapper>
44
</div>
55
<div *ngIf="bShowAppShell$ && portalTemplate === 'wss'">
6-
<component-mapper name="WssNavBar" [props]="{ pConn$, appName$, homePage: pages$[0], pages$: links, caseTypes$ }"></component-mapper>
7-
</div>
8-
<div [ngClass]="{ 'appshell-main': portalTemplate !== 'wss', 'appshell-main-wss': portalTemplate === 'wss' }">
9-
<div *ngFor="let kid of arChildren$">
10-
<div *ngIf="kid.getPConnect().getComponentName() == 'ViewContainer'">
11-
<component-mapper name="ViewContainer" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
12-
</div>
13-
</div>
14-
</div>
15-
<div *ngIf="portalTemplate === 'wss'">
16-
<app-footer></app-footer>
6+
<component-mapper
7+
name="WssNavBar"
8+
[props]="{ pConn$, appName$, homePage: pages$[0], pages$: links, caseTypes$, arChildren$, portalLogoImage$: imageURL }"
9+
></component-mapper>
1710
</div>
1811
</div>

src/app/_samples/mediaco/overrides/app-shell/app-shell.component.ts

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ import { Component, OnInit, Input, NgZone, forwardRef, OnDestroy } from '@angula
22
import { CommonModule } from '@angular/common';
33
import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
44
import { Subscription } from 'rxjs';
5-
import { AngularPConnectData, AngularPConnectService } from '@pega/angular-sdk-components';
5+
import { AngularPConnectData, AngularPConnectService, Utils } from '@pega/angular-sdk-components';
66
import { ErrorMessagesService } from '@pega/angular-sdk-components';
77
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
8-
import { FooterComponent } from '../../components/footer/footer.component';
98

109
interface IPage {
1110
classID: string;
@@ -32,7 +31,7 @@ interface AppShellProps {
3231
selector: 'app-app-shell',
3332
templateUrl: './app-shell.component.html',
3433
styleUrls: ['./app-shell.component.scss'],
35-
imports: [CommonModule, MatSnackBarModule, FooterComponent, forwardRef(() => ComponentMapperComponent)]
34+
imports: [CommonModule, MatSnackBarModule, forwardRef(() => ComponentMapperComponent)]
3635
})
3736
export class AppShellComponent implements OnInit, OnDestroy {
3837
@Input() pConn$: typeof PConnect;
@@ -45,19 +44,22 @@ export class AppShellComponent implements OnInit, OnDestroy {
4544
caseTypes$?: object[];
4645
arChildren$: any[];
4746
bShowAppShell$ = false;
48-
appName$ = 'PEGA';
47+
appName$ = '';
4948
errorMessagesSubscription: Subscription;
5049
sErrorMessages = '';
5150
snackBarRef: any;
5251
bOkDisplayError = false;
5352
portalTemplate: string;
5453
links: any = [];
54+
imageURL: string | Blob;
55+
localizedVal = PCore.getLocaleUtils().getLocaleValue;
5556

5657
constructor(
5758
private angularPConnect: AngularPConnectService,
5859
private erService: ErrorMessagesService,
5960
private snackBar: MatSnackBar,
60-
private ngZone: NgZone
61+
private ngZone: NgZone,
62+
private utils: Utils
6163
) {}
6264

6365
ngOnInit() {
@@ -68,6 +70,8 @@ export class AppShellComponent implements OnInit, OnDestroy {
6870

6971
this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as AppShellProps;
7072

73+
this.portalTemplate = this.configProps$.portalTemplate;
74+
7175
// making a copy, so can add info
7276
this.pages$ = this.configProps$.pages;
7377

@@ -79,6 +83,11 @@ export class AppShellComponent implements OnInit, OnDestroy {
7983
this.bShowAppShell$ = true;
8084
}
8185

86+
/* TODO: We're setting the `pyPortalTemplate` for now, this would be handled by the CoreJS in the future releases */
87+
if (this.portalTemplate === 'wss') {
88+
PCore.getEnvironmentInfo().setEnvironmentInfo({ ...PCore.getEnvironmentInfo().environmentInfoObject, pyPortalTemplate: 'wss' } as any);
89+
}
90+
8291
// @ts-ignore - Property 'pyCaseTypesAvailableToCreateDP' does not exist on type pxApplication
8392
const caseTypesAvailableToCreateDP = PCore.getEnvironmentInfo().environmentInfoObject?.pxApplication?.pyCaseTypesAvailableToCreateDP;
8493
if (caseTypesAvailableToCreateDP) {
@@ -100,8 +109,6 @@ export class AppShellComponent implements OnInit, OnDestroy {
100109

101110
this.arChildren$ = this.pConn$.getChildren();
102111

103-
this.portalTemplate = this.configProps$.portalTemplate;
104-
105112
// handle showing and hiding the progress spinner
106113
this.errorMessagesSubscription = this.erService.getMessage().subscribe(message => {
107114
this.showDismissErrorMessages(message);
@@ -138,6 +145,12 @@ export class AppShellComponent implements OnInit, OnDestroy {
138145
updateSelf() {
139146
this.configProps$ = this.pConn$.resolveConfigProps(this.pConn$.getConfigProps()) as AppShellProps;
140147

148+
const showAppName = this.configProps$.showAppName;
149+
const envInfo = PCore.getEnvironmentInfo();
150+
const appNameToDisplay = showAppName ? envInfo.getApplicationLabel() : '';
151+
const portalClass = this.pConn$.getValue('.classID', ''); // 2nd arg empty string until typedef marked correctly
152+
const envPortalName = envInfo.getPortalName();
153+
141154
this.ngZone.run(() => {
142155
// making a copy, so can add info
143156
this.pages$ = this.configProps$.pages;
@@ -149,6 +162,30 @@ export class AppShellComponent implements OnInit, OnDestroy {
149162
this.caseTypes$ = this.configProps$.caseTypes;
150163
this.arChildren$ = this.pConn$.getChildren();
151164
});
165+
166+
const portalLogo = this.configProps$.portalLogo;
167+
// using the default icon then fetch it from the static folder (not auth involved)
168+
if (
169+
!portalLogo ||
170+
portalLogo.toLowerCase().includes('pzpega-logo-mark') ||
171+
portalLogo.toLowerCase().includes('py-logo') ||
172+
portalLogo.toLowerCase().includes('py-full-logo')
173+
) {
174+
const portalLogoImage = this.utils.getIconPath(this.utils.getSDKStaticContentUrl()).concat('pzpega-logo-mark.svg');
175+
this.imageURL = portalLogoImage;
176+
}
177+
// not using default icon to fetch it using the way which uses authentication
178+
else {
179+
PCore.getAssetLoader()
180+
.getSvcImageUrl(portalLogo)
181+
.then(data => {
182+
this.imageURL = data;
183+
})
184+
.catch(() => {
185+
console.error(`${this.localizedVal('Unable to load the image for the portal logo/icon with the insName', 'AppShell')}:${portalLogo}`);
186+
});
187+
}
188+
this.appName$ = this.localizedVal(appNameToDisplay || '', '', `${portalClass}!PORTAL!${envPortalName}`.toUpperCase());
152189
}
153190

154191
// fpr show/hiding error messages in the SnackBar component
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<div style="margin-bottom: '2rem'">
2+
<div class="background-image-style" [ngStyle]="{ 'background-image': getUrl() }">
3+
<div class="background-style content">
4+
<div>
5+
<h1 class="title">{{ title }}</h1>
6+
<p class="message">{{ message }}</p>
7+
</div>
8+
</div>
9+
</div>
10+
<div
11+
[ngClass]="{
12+
'psdk-grid-filter-1': this.layout$ === 'two-column',
13+
'psdk-grid-filter-wide-narrow': this.layout$ === 'wide-narrow',
14+
'psdk-grid-filter-narrow-wide': this.layout$ === 'narrow-wide'
15+
}"
16+
>
17+
<component-mapper
18+
*ngIf="arChildren$[0]"
19+
[name]="arChildren$[0].getPConnect().getComponentName()"
20+
[props]="{ pConn$: arChildren$[0].getPConnect(), formGroup$ }"
21+
errorMsg="Region wants component not yet available: {{ arChildren$[0].getPConnect().getComponentName() }}"
22+
></component-mapper>
23+
<component-mapper
24+
*ngIf="arChildren$[1]"
25+
[name]="arChildren$[1].getPConnect().getComponentName()"
26+
[props]="{ pConn$: arChildren$[1].getPConnect(), formGroup$ }"
27+
errorMsg="Region wants component not yet available: {{ arChildren$[1].getPConnect().getComponentName() }}"
28+
></component-mapper>
29+
</div>
30+
</div>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
.psdk-grid-filter-1 {
2+
display: grid;
3+
grid-template-columns: repeat(3, minmax(0, 1fr));
4+
column-gap: calc(2 * 0.5rem);
5+
row-gap: calc(2 * 0.5rem);
6+
align-items: start;
7+
}
8+
9+
.psdk-grid-filter-wide-narrow {
10+
display: grid;
11+
grid-template-columns: 7fr 3fr;
12+
column-gap: calc(2 * 0.5rem);
13+
row-gap: calc(2 * 0.5rem);
14+
align-items: start;
15+
padding: 1rem;
16+
}
17+
18+
.psdk-grid-filter-narrow-wide {
19+
display: grid;
20+
grid-template-columns: 3fr 7fr;
21+
column-gap: calc(2 * 0.5rem);
22+
row-gap: calc(2 * 0.5rem);
23+
align-items: start;
24+
}
25+
26+
.background-image-style {
27+
margin-left: -16px;
28+
margin-right: -16px;
29+
height: calc(19rem);
30+
background-size: cover;
31+
background-position: center center;
32+
}
33+
34+
.background-style {
35+
background-color: transparent;
36+
color: var(--app-inverse-form-color);
37+
width: 100%;
38+
height: 100%;
39+
text-align: center;
40+
}
41+
42+
.content {
43+
display: flex;
44+
flex-direction: column;
45+
justify-content: center;
46+
align-items: center;
47+
gap: calc(0.5rem);
48+
}
49+
50+
.title {
51+
margin: 0rem;
52+
font-size: 1.728rem;
53+
font-weight: 600;
54+
}
55+
56+
.message {
57+
margin: 0;
58+
font-size: 1rem;
59+
font-weight: 400;
60+
}
61+
62+
.banner-layout {
63+
padding: 1rem;
64+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { BannerComponent } from './banner.component';
4+
5+
describe('BannerComponent', () => {
6+
let component: BannerComponent;
7+
let fixture: ComponentFixture<BannerComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [BannerComponent]
12+
}).compileComponents();
13+
14+
fixture = TestBed.createComponent(BannerComponent);
15+
component = fixture.componentInstance;
16+
fixture.detectChanges();
17+
});
18+
19+
it('should create', () => {
20+
expect(component).toBeTruthy();
21+
});
22+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { CommonModule } from '@angular/common';
2+
import { FormGroup } from '@angular/forms';
3+
import { Component, Input, forwardRef } from '@angular/core';
4+
import { ComponentMapperComponent } from '@pega/angular-sdk-components';
5+
6+
@Component({
7+
selector: 'app-banner',
8+
templateUrl: './banner.component.html',
9+
styleUrls: ['./banner.component.scss'],
10+
imports: [CommonModule, forwardRef(() => ComponentMapperComponent)]
11+
})
12+
export class BannerComponent {
13+
@Input() pConn$: typeof PConnect;
14+
@Input() formGroup$: FormGroup;
15+
16+
@Input() arChildren$: any[];
17+
@Input() title: string;
18+
@Input() message: any;
19+
@Input() backgroundImage: string;
20+
@Input() layout$: string;
21+
22+
getUrl() {
23+
return `url(${this.backgroundImage})`;
24+
}
25+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<mat-sidenav-container class="sidenav-container" autosize>
2+
<mat-sidenav #drawer class="sidenav" mode="side" opened="true" [style.width]="collapsed ? '5rem' : '15rem'">
3+
<!-- Add [class.collapsed-mode]="collapsed" here -->
4+
<mat-nav-list [class.collapsed-mode]="collapsed">
5+
<!-- Toggle Button -->
6+
<div class="nav-item-container toggle-header" (click)="toggleMenu()">
7+
<button type="button" mat-icon-button [disableRipple]="true">
8+
<mat-icon>{{ collapsed ? 'menu' : 'cancel' }}</mat-icon>
9+
</button>
10+
</div>
11+
12+
<!-- Home Button -->
13+
<!-- <div mat-list-item> -->
14+
<!-- Added 'nav-item-container' class for specific styling -->
15+
<div class="flex-box nav-item-container toggle-header" [class.selected]="activePage === 'Self-service Main page'">
16+
<button type="button" mat-icon-button [disableRipple]="true" (click)="navPanelButtonClick(homePage)">
17+
<mat-icon>home</mat-icon>
18+
</button>
19+
<!-- Only show text if you want it in collapsed mode too, otherwise hide or style it -->
20+
<div mat-button class="psdk-nav-button-span">Home</div>
21+
</div>
22+
<!-- </div> -->
23+
24+
<!-- Dynamic Pages -->
25+
<div *ngFor="let page of navPages$">
26+
<div class="flex-box mat-list-item nav-item-container toggle-header" [class.selected]="activePage === page.pyLabel">
27+
<button type="button" mat-icon-button [disableRipple]="true" (click)="navPanelButtonClick(page)">
28+
<mat-icon>dashboard</mat-icon>
29+
</button>
30+
<div mat-button class="psdk-nav-button-span">{{ page.pyDefaultHeading }}</div>
31+
</div>
32+
</div>
33+
</mat-nav-list>
34+
</mat-sidenav>
35+
<mat-sidenav-content>
36+
<!-- Top Toolbar -->
37+
<mat-toolbar *ngIf="activePage === 'Self-service Main page'" style="position: relative; background: transparent">
38+
<mat-toolbar-row mat-icon-button style="justify-content: space-between">
39+
<div class="psdk-nav-header" (click)="navPanelButtonClick(homePage)">
40+
<div>
41+
<img src="{{ portalLogoImage$ }}" class="psdk-nav-logo" />
42+
</div>
43+
<div class="psdk-nav-portal-info">
44+
<div class="psdk-nav-portal-app">{{ appName$ }}</div>
45+
</div>
46+
</div>
47+
48+
<div>
49+
<mat-list class="horizontal-list">
50+
<mat-list-item [matMenuTriggerFor]="menu" class="psdk-profile-list-item">
51+
<div class="flex-box">
52+
<mat-icon class="circle-icon">person</mat-icon>
53+
</div>
54+
</mat-list-item>
55+
<mat-menu #menu="matMenu">
56+
<button mat-menu-item (click)="navPanelLogoutClick()">{{ localizedVal('Log off', localeCategory) }}</button>
57+
</mat-menu>
58+
<mat-list-item>
59+
<div class="flex-box">
60+
<mat-icon class="circle-icon">notifications</mat-icon>
61+
</div>
62+
</mat-list-item>
63+
</mat-list>
64+
</div>
65+
</mat-toolbar-row>
66+
</mat-toolbar>
67+
68+
<div *ngFor="let kid of arChildren$">
69+
<div *ngIf="kid.getPConnect().getComponentName() == 'ViewContainer'">
70+
<component-mapper name="ViewContainer" [props]="{ pConn$: kid.getPConnect() }"></component-mapper>
71+
</div>
72+
</div>
73+
<app-footer></app-footer>
74+
</mat-sidenav-content>
75+
</mat-sidenav-container>

0 commit comments

Comments
 (0)