Skip to content

Commit a3cfd6a

Browse files
committed
Action hub
1 parent df5ceeb commit a3cfd6a

5 files changed

Lines changed: 169 additions & 0 deletions

File tree

src/app/app.routes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import { Routes } from '@angular/router';
33
export const routes: Routes = [
44
{
55
path: '',
6+
pathMatch: 'full',
7+
loadComponent: () => import('./hub/hub'),
8+
},
9+
{
10+
path: 'animal-profiles',
611
loadComponent: () => import('./animal-profiles/list/list'),
712
},
813
{

src/app/hub/hub.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<sky-action-hub
2+
data-sky-id="action-hub"
3+
[needsAttention]="needsAttention()"
4+
[relatedLinks]="relatedLinks"
5+
[title]="title"
6+
>
7+
<sky-action-hub-content>
8+
<sky-box headingText="Welcome to SKY UX">
9+
<sky-box-content>
10+
<app-welcome-to-skyux />
11+
</sky-box-content>
12+
</sky-box>
13+
</sky-action-hub-content>
14+
</sky-action-hub>

src/app/hub/hub.spec.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
2+
import { provideLocationMocks } from '@angular/common/testing';
3+
import { ComponentFixture, TestBed } from '@angular/core/testing';
4+
import { provideRouter } from '@angular/router';
5+
import { expectAsync } from '@skyux-sdk/testing';
6+
import { SkyActionHubHarness } from '@skyux/pages/testing';
7+
8+
import { Hub } from './hub';
9+
import { MockData } from '../services/data/mock-data';
10+
import { Data } from '../services/data/data';
11+
12+
describe('Hub', () => {
13+
let component: Hub;
14+
let fixture: ComponentFixture<Hub>;
15+
let harness: SkyActionHubHarness;
16+
17+
beforeEach(async () => {
18+
TestBed.configureTestingModule({
19+
imports: [Hub],
20+
providers: [
21+
provideLocationMocks(),
22+
provideRouter([]),
23+
MockData,
24+
{
25+
provide: Data,
26+
useExisting: MockData,
27+
},
28+
],
29+
});
30+
fixture = TestBed.createComponent(Hub);
31+
component = fixture.componentInstance;
32+
fixture.detectChanges();
33+
harness = await TestbedHarnessEnvironment.loader(fixture).getHarness(
34+
SkyActionHubHarness.with({
35+
dataSkyId: 'action-hub',
36+
}),
37+
);
38+
});
39+
40+
it('should show a count of animals needing attention', async () => {
41+
expect(component).toBeTruthy();
42+
const dataService = TestBed.inject(Data);
43+
dataService.load([]);
44+
fixture.detectChanges();
45+
await fixture.whenStable();
46+
const items = await harness.getNeedsAttentionItems();
47+
expect(items).toHaveSize(1);
48+
expect(await items[0].getText()).toEqual('0 animals need attention');
49+
dataService.load([
50+
{
51+
bio: 'bio',
52+
createdAt: new Date(),
53+
updatedAt: new Date(),
54+
breed: 'breed',
55+
gender: '',
56+
images: [],
57+
name: 'name1',
58+
id: 'id1',
59+
needsAttention: true,
60+
},
61+
{
62+
bio: 'bio',
63+
createdAt: new Date(),
64+
updatedAt: new Date(),
65+
breed: 'breed',
66+
gender: '',
67+
images: [],
68+
name: 'name2',
69+
id: 'id2',
70+
needsAttention: false,
71+
},
72+
]);
73+
fixture.detectChanges();
74+
await fixture.whenStable();
75+
expect(await (await harness.getNeedsAttentionItems())[0].getText()).toEqual(
76+
'1 animal needs attention',
77+
);
78+
});
79+
80+
it('should be accessible', async () => {
81+
await fixture.whenStable();
82+
const element = fixture.nativeElement as HTMLElement;
83+
await expectAsync(element).toBeAccessible();
84+
});
85+
});

src/app/hub/hub.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
2+
import { SkyBoxModule } from '@skyux/layout';
3+
import { SkyActionHubModule } from '@skyux/pages';
4+
5+
import { parentLink } from '../animal-profiles/parent-link';
6+
import { Data } from '../services/data/data';
7+
import { welcomeToSkyuxLinks } from '../welcome-to-skyux/welcome-to-skyux-links';
8+
import { WelcomeToSkyux } from '../welcome-to-skyux/welcome-to-skyux';
9+
10+
@Component({
11+
selector: 'app-hub',
12+
imports: [SkyActionHubModule, SkyBoxModule, WelcomeToSkyux],
13+
templateUrl: './hub.html',
14+
changeDetection: ChangeDetectionStrategy.OnPush,
15+
})
16+
export class Hub {
17+
protected readonly needsAttention = computed(() => {
18+
const needsAttentionCount = this.#needsAttentionCount();
19+
const singular = needsAttentionCount === 1;
20+
return [
21+
{
22+
title: `${needsAttentionCount} animal${singular ? '' : 's'} need${singular ? 's' : ''} attention`,
23+
permalink: { route: { commands: ['animal-profiles'] } },
24+
},
25+
];
26+
});
27+
protected readonly relatedLinks = welcomeToSkyuxLinks.map((link) => ({
28+
label: link.label,
29+
permalink: {
30+
url: link.url,
31+
},
32+
}));
33+
protected readonly title = parentLink.label;
34+
35+
readonly #dataService = inject(Data);
36+
readonly #needsAttentionCount = computed(() =>
37+
this.#dataService
38+
.list()
39+
.reduce((count, profile) => count + (profile.needsAttention ? 1 : 0), 0),
40+
);
41+
}
42+
43+
export default Hub;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const welcomeToSkyuxLinks = [
2+
{
3+
label: 'SKY UX Documentation',
4+
url: 'https://developer.blackbaud.com/skyux',
5+
},
6+
{
7+
label: 'SKY UX GitHub',
8+
url: 'https://github.com/blackbaud/skyux',
9+
},
10+
{
11+
label: 'SKY Developer',
12+
url: 'https://developer.blackbaud.com/',
13+
},
14+
{
15+
label: 'Learn Angular',
16+
url: 'https://angular.dev/tutorials/learn-angular',
17+
},
18+
{
19+
label: 'Get Started with SKY UX',
20+
url: 'https://developer.blackbaud.com/skyux/learn/overview',
21+
},
22+
];

0 commit comments

Comments
 (0)