Added more staff data and staff-card page

This commit is contained in:
Erik Tiekstra
2021-04-12 13:52:20 +02:00
parent 1ee6ca9251
commit 0b0dd8e107
18 changed files with 310 additions and 23 deletions

View File

@@ -1,4 +1,4 @@
<div [ngClass]="appClass">
<div class="dafa">
<dafa-skip-to-content mainContentId="dafa-main-content"></dafa-skip-to-content>
<header class="dafa__header">

View File

@@ -2,7 +2,7 @@ import { NavigationBreadcrumbsItem } from '@af/digi-ng/_navigation/navigation-br
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { User } from '@dafa-models/user.model';
import { mapPathToPageName } from '@dafa-utils/map-path-to-page-name.util';
import { mapPathsToBreadcrumbs } from '@dafa-utils/map-paths-to-breadcrumbs.util';
import { BehaviorSubject } from 'rxjs';
import { filter } from 'rxjs/operators';
import { UnsubscribeDirective } from './directives/unsubscribe.directive';
@@ -14,7 +14,6 @@ import { UnsubscribeDirective } from './directives/unsubscribe.directive';
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent extends UnsubscribeDirective {
path = '';
user: User = {
id: 'fake-user',
name: 'Fake user',
@@ -35,24 +34,9 @@ export class AppComponent extends UnsubscribeDirective {
super();
super.unsubscribeOnDestroy(
this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
const paths = this.router.url.split('/');
this._breadcrumbsItems$.next([
this.startBreadcrumb,
...[...paths]
.filter(path => !!path)
.map(path => ({
text: mapPathToPageName(path),
routerLink: paths.slice(0, paths.length - 1).join('/'),
})),
]);
this.path = paths[1].split('?')[0] || '';
const paths = this.router.url.split('/').filter(path => !!path);
this._breadcrumbsItems$.next(mapPathsToBreadcrumbs(paths, this.startBreadcrumb));
})
);
}
get appClass(): string {
return `dafa dafa--${this.path.length ? this.path : 'home'}`;
}
}

View File

@@ -1,7 +1,7 @@
export const Navigation = {
administration: 'Administration',
'skapa-konto': 'Skapa nytt konto',
personal: 'Personal',
personal: 'Hantera personal',
'mina-deltagare': 'Mina deltagare',
avrop: 'Avrop',
meddelanden: 'Meddelanden',

View File

@@ -0,0 +1,6 @@
export interface DateFormatOptions {
year?: 'short' | 'long' | 'numeric';
month?: 'short' | 'long' | 'numeric';
day?: 'short' | 'long' | 'numeric';
weekday?: 'short' | 'long' | 'numeric';
}

View File

@@ -8,3 +8,15 @@ export interface Staff {
service: string;
fullName?: string;
}
export interface StaffDetail extends Staff {
languages: string[];
outOfOffice: {
start: Date;
end: Date;
}[];
authorisations: string[];
phone: string;
email: string;
ssn: string;
}

View File

@@ -13,6 +13,10 @@ const routes: Routes = [
path: 'personal',
loadChildren: () => import('./pages/staff/staff.module').then(m => m.StaffModule),
},
{
path: 'personal/:id',
loadChildren: () => import('./pages/staff-card/staff-card.module').then(m => m.StaffCardModule),
},
{
path: 'skapa-konto',
loadChildren: () => import('./pages/create-account/create-account.module').then(m => m.CreateAccountModule),

View File

@@ -0,0 +1,63 @@
<section class="staff-card">
<digi-typography *ngIf="detailedStaffData$ | async as detailedStaffData; else loadingRef">
<h1>{{ detailedStaffData.fullName }}</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus accusantium sit, reprehenderit, esse suscipit
quis similique harum est eum eveniet aspernatur delectus magni asperiores porro aliquam voluptate! Architecto,
perferendis commodi.
</p>
<div class="staff-card__contents">
<div class="staff-card__column">
<h2>Kontaktuppgifter</h2>
<dl>
<dt>Personnummer</dt>
<dd>{{ detailedStaffData.ssn || '' }}</dd>
<dt>Personal-ID</dt>
<dd>{{ detailedStaffData.staffId || '' }}</dd>
<dt>Telefon arbete</dt>
<dd>{{ detailedStaffData.phone || '' }}</dd>
<dt>Mailadress arbete</dt>
<dd>{{ detailedStaffData.email || '' }}</dd>
</dl>
</div>
<div class="staff-card__column">
<h2>Uppgifter om arbete</h2>
<dl>
<dt>Behörighet</dt>
<ng-container *ngIf="detailedStaffData.authorisations.length; else emptyDD">
<dd *ngFor="let item of detailedStaffData.authorisations">
{{ item }}
</dd>
</ng-container>
<dt>Aktivt i arbete</dt>
<dd>{{ detailedStaffData.active ? 'Ja' : 'Nej' }}</dd>
<dt>Frånvaroperiod</dt>
<ng-container *ngIf="detailedStaffData.outOfOffice.length; else emptyDD">
<dd *ngFor="let date of detailedStaffData.outOfOffice">
{{ date.start | localDate }} - {{ date.end | localDate }}
</dd>
</ng-container>
<dt>Tjänst</dt>
<dd>{{ detailedStaffData.service || '' }}</dd>
<dt>Språk</dt>
<dd>{{ detailedStaffData.languages?.join(', ') }}</dd>
</dl>
</div>
</div>
</digi-typography>
</section>
<ng-template #loadingRef>
<digi-ng-skeleton-base [afCount]="3" afText="Laddar personalkortet"></digi-ng-skeleton-base>
</ng-template>
<ng-template #emptyDD>
<dd>
<span aria-hidden="true">-</span>
<span class="dafa__a11y-sr-only">Info saknas</span>
</dd>
</ng-template>

View File

@@ -0,0 +1,38 @@
@import 'variables/gutters';
.staff-card {
&__contents {
display: flex;
gap: $digi--layout--gutter--l;
padding: $digi--layout--gutter--l;
background-color: var(--digi--ui--color--background--secondary);
h2 {
margin-top: 0;
}
}
&__column {
width: 100%;
}
dl {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.5rem 2rem;
}
dt,
dd {
margin: 0;
}
dt {
grid-column: 1;
font-weight: var(--digi--typography--font-weight--semibold);
}
dd {
grid-column: 2;
}
}

View File

@@ -0,0 +1,27 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { StaffCardComponent } from './staff-card.component';
describe('StaffCardComponent', () => {
let component: StaffCardComponent;
let fixture: ComponentFixture<StaffCardComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [StaffCardComponent],
imports: [RouterTestingModule],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(StaffCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,27 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive';
import { Staff } from '@dafa-models/staff.model';
import { StaffService } from '@dafa-services/api/staff.service';
import { Observable } from 'rxjs';
@Component({
selector: 'dafa-staff-card',
templateUrl: './staff-card.component.html',
styleUrls: ['./staff-card.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StaffCardComponent extends UnsubscribeDirective {
detailedStaffData$: Observable<Staff>;
constructor(private activatedRoute: ActivatedRoute, private staffService: StaffService) {
super();
super.unsubscribeOnDestroy(
this.activatedRoute.params.subscribe(({ id }) => {
console.log(id);
this.detailedStaffData$ = this.staffService.getDetailedStaffData(id);
})
);
}
}

View File

@@ -0,0 +1,18 @@
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
import { StaffCardComponent } from './staff-card.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [StaffCardComponent],
imports: [
CommonModule,
RouterModule.forChild([{ path: '', component: StaffCardComponent }]),
DigiNgSkeletonBaseModule,
LocalDatePipeModule,
],
})
export class StaffCardModule {}

View File

@@ -51,7 +51,9 @@
</thead>
<tbody>
<tr *ngFor="let staff of pagedStaff">
<th scope="row">{{ staff.firstName }} {{ staff.lastName }}</th>
<th scope="row">
<a [routerLink]="staff.id" class="staff-list__link">{{ staff.fullName }}</a>
</th>
<td>{{ staff.staffId }}</td>
<td>{{ staff.kommun }}</td>
<td>{{ staff.active ? 'Ja' : 'Nej' }}</td>

View File

@@ -1,12 +1,13 @@
import { DigiNgTableModule } from '@af/digi-ng/_table/table';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { StaffListComponent } from './staff-list.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [StaffListComponent],
imports: [CommonModule, DigiNgTableModule],
imports: [CommonModule, RouterModule, DigiNgTableModule],
exports: [StaffListComponent],
})
export class StaffListModule {}

View File

@@ -27,6 +27,7 @@ export class StaffService {
}))
)
);
private _staffSortBy$ = new BehaviorSubject<SortBy | null>({ key: 'fullName', reverse: false });
public staffSortBy$: Observable<SortBy> = this._staffSortBy$.asObservable();
private _searchFilter$ = new BehaviorSubject<string>('');
@@ -42,6 +43,15 @@ export class StaffService {
})
);
public getDetailedStaffData(id: string): Observable<Staff> {
return this.httpClient.get<Staff>(`${environment.apiBase}/staff/${id}`).pipe(
map(staff => ({
...staff,
fullName: `${staff.firstName} ${staff.lastName}`,
}))
);
}
public setSearchFilter(value: string) {
this._searchFilter$.next(value);
}

View File

@@ -0,0 +1,11 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { LocalDatePipe } from './local-date.pipe';
@NgModule({
declarations: [LocalDatePipe],
imports: [CommonModule],
exports: [LocalDatePipe],
providers: [LocalDatePipe],
})
export class LocalDatePipeModule {}

View File

@@ -0,0 +1,26 @@
import { Pipe, PipeTransform } from '@angular/core';
import { DateFormatOptions } from '@dafa-models/date-format-options.model';
@Pipe({
name: 'localDate',
})
export class LocalDatePipe implements PipeTransform {
private defaultFormatOptions: DateFormatOptions = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
};
private defaultLocale = 'sv-SE';
transform(
date: string | Date,
formatOptions: DateFormatOptions = this.defaultFormatOptions,
locale: string = this.defaultLocale
): string {
if (!date) {
console.warn('WARNING: No date provided.');
return '';
}
return new Date(date).toLocaleDateString(locale, formatOptions);
}
}

View File

@@ -0,0 +1,25 @@
import { NavigationBreadcrumbsItem } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
import { mapPathToPageName } from './map-path-to-page-name.util';
export function mapPathsToBreadcrumbs(
paths: string[],
startBreadcrumb?: NavigationBreadcrumbsItem
): NavigationBreadcrumbsItem[] {
const breadcrumbs = [
...(startBreadcrumb ? [startBreadcrumb] : []),
...paths.map((path, index) => ({
text: mapPathToPageName(path),
routerLink: paths.slice(0, index + 1).join('/'),
})),
];
if (isStaffCardRoute(paths)) {
breadcrumbs[breadcrumbs.length - 1].text = 'Personalkort';
}
return breadcrumbs;
}
function isStaffCardRoute(paths: string[]): boolean {
return paths.length === 3 && paths[1] === 'personal';
}