Added more staff data and staff-card page
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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'}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface DateFormatOptions {
|
||||
year?: 'short' | 'long' | 'numeric';
|
||||
month?: 'short' | 'long' | 'numeric';
|
||||
day?: 'short' | 'long' | 'numeric';
|
||||
weekday?: 'short' | 'long' | 'numeric';
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 {}
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
25
apps/dafa-web/src/app/utils/map-paths-to-breadcrumbs.util.ts
Normal file
25
apps/dafa-web/src/app/utils/map-paths-to-breadcrumbs.util.ts
Normal 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';
|
||||
}
|
||||
Reference in New Issue
Block a user