Renamed staff to employees

This commit is contained in:
Erik Tiekstra
2021-05-04 14:44:48 +02:00
parent e56b92c0d9
commit 067b25c3aa
27 changed files with 289 additions and 287 deletions
@@ -1,9 +1,9 @@
import { Agency } from '@dafa-models/agency.model'; import { Agency } from '@dafa-models/agency.model';
import { Participant } from './participant.model'; import { Participant } from './participant.model';
export interface Staff { export interface Employee {
id: string; id: string;
staffId: string; employeeId: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
utforandeverksamhet: string; utforandeverksamhet: string;
@@ -12,7 +12,7 @@ export interface Staff {
fullName?: string; fullName?: string;
} }
export interface StaffDetail extends Staff { export interface EmployeeDetail extends Employee {
languages: string[]; languages: string[];
outOfOffice: { outOfOffice: {
start: Date; start: Date;
@@ -1,7 +1,7 @@
import { Employee } from './employee.model';
import { Participant } from './participant.model'; import { Participant } from './participant.model';
import { Staff } from './staff.model';
export interface SortBy { export interface SortBy {
key: keyof Participant | keyof Staff; key: keyof Participant | keyof Employee;
reverse: boolean; reverse: boolean;
} }
@@ -11,11 +11,11 @@ const routes: Routes = [
}, },
{ {
path: 'personal', path: 'personal',
loadChildren: () => import('./pages/staff/staff.module').then(m => m.StaffModule), loadChildren: () => import('./pages/employees/employees.module').then(m => m.EmployeesModule),
}, },
{ {
path: 'personal/:id', path: 'personal/:id',
loadChildren: () => import('./pages/staff-card/staff-card.module').then(m => m.StaffCardModule), loadChildren: () => import('./pages/employee-card/employee-card.module').then(m => m.EmployeeCardModule),
}, },
{ {
path: 'skapa-konto', path: 'skapa-konto',
@@ -1,12 +1,9 @@
import { RadiobuttonModel } from '@af/digi-ng/_form/form-radiobutton-group';
import { FormSelectBaseItem } from '@af/digi-ng/_form/form-select-base'; import { FormSelectBaseItem } from '@af/digi-ng/_form/form-select-base';
import { PopoverDirection, PopoverOrientation } from '@af/digi-ng/_popover/popover';
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms'; import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { Service } from '@dafa-enums/service.enum'; import { Service } from '@dafa-enums/service.enum';
import { OutOfOfficeDate } from '@dafa-models/out-of-office-date.model'; import { EmployeeService } from '@dafa-services/api/employee.service';
import { StaffService } from '@dafa-services/api/staff.service';
import { RequiredValidator } from '@dafa-validators/required.validator'; import { RequiredValidator } from '@dafa-validators/required.validator';
import { SocialSecurityNumberValidator } from '@dafa-validators/social-security-number.validator'; import { SocialSecurityNumberValidator } from '@dafa-validators/social-security-number.validator';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
@@ -38,12 +35,12 @@ export class CreateAccountComponent {
}, },
]; ];
constructor(private formBuilder: FormBuilder, private staffService: StaffService, private router: Router) { constructor(private formBuilder: FormBuilder, private employeeService: EmployeeService, private router: Router) {
this.formGroup = this.formBuilder.group({ this.formGroup = this.formBuilder.group({
firstName: this.formBuilder.control('', [RequiredValidator('Förnamn')]), firstName: this.formBuilder.control('', [RequiredValidator('Förnamn')]),
lastName: this.formBuilder.control('', [RequiredValidator('Efternamn')]), lastName: this.formBuilder.control('', [RequiredValidator('Efternamn')]),
ssn: this.formBuilder.control('', [RequiredValidator('Personnummer'), SocialSecurityNumberValidator()]), ssn: this.formBuilder.control('', [RequiredValidator('Personnummer'), SocialSecurityNumberValidator()]),
staffId: this.formBuilder.control('', [RequiredValidator('Personal-ID')]), employeeId: this.formBuilder.control('', [RequiredValidator('Personal-ID')]),
service: this.formBuilder.control(''), service: this.formBuilder.control(''),
permissions: this.formBuilder.control(false), permissions: this.formBuilder.control(false),
participant: this.formBuilder.control(false), participant: this.formBuilder.control(false),
@@ -104,7 +101,7 @@ export class CreateAccountComponent {
delete submittableValues.outOfOfficeStart; delete submittableValues.outOfOfficeStart;
delete submittableValues.outOfOfficeEnd; delete submittableValues.outOfOfficeEnd;
const post = this.staffService.createAccount(submittableValues).subscribe({ const post = this.employeeService.createAccount(submittableValues).subscribe({
next: id => { next: id => {
this.router.navigate(['/administration', 'personal', id]); this.router.navigate(['/administration', 'personal', id]);
}, },
@@ -1,6 +1,6 @@
<section class="staff-card"> <section class="employee-card">
<digi-typography *ngIf="detailedStaffData$ | async as detailedStaffData; else loadingRef"> <digi-typography *ngIf="detailedEmployeeData$ | async as detailedEmployeeData; else loadingRef">
<h1>{{ detailedStaffData.fullName }}</h1> <h1>{{ detailedEmployeeData.fullName }}</h1>
<p> <p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus accusantium sit, reprehenderit, esse suscipit 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, quis similique harum est eum eveniet aspernatur delectus magni asperiores porro aliquam voluptate! Architecto,
@@ -13,16 +13,16 @@
<dl> <dl>
<dt>Personnummer</dt> <dt>Personnummer</dt>
<dd>{{ detailedStaffData.ssn || '' }}</dd> <dd>{{ detailedEmployeeData.ssn || '' }}</dd>
<dt>Personal-ID</dt> <dt>Personal-ID</dt>
<dd>{{ detailedStaffData.staffId || '' }}</dd> <dd>{{ detailedEmployeeData.employeeId || '' }}</dd>
<dt>Telefon arbete</dt> <dt>Telefon arbete</dt>
<dd *ngIf="detailedStaffData.phone; else emptyDD"> <dd *ngIf="detailedEmployeeData.phone; else emptyDD">
<a [attr.href]="'tel:' + detailedStaffData.phone">{{ detailedStaffData.phone }}</a> <a [attr.href]="'tel:' + detailedEmployeeData.phone">{{ detailedEmployeeData.phone }}</a>
</dd> </dd>
<dt>Mailadress arbete</dt> <dt>Mailadress arbete</dt>
<dd *ngIf="detailedStaffData.email; else emptyDD"> <dd *ngIf="detailedEmployeeData.email; else emptyDD">
<a [attr.href]="'mailto:' + detailedStaffData.email">{{ detailedStaffData.email }}</a> <a [attr.href]="'mailto:' + detailedEmployeeData.email">{{ detailedEmployeeData.email }}</a>
</dd> </dd>
</dl> </dl>
</div> </div>
@@ -32,31 +32,31 @@
<dl> <dl>
<dt>Behörighet</dt> <dt>Behörighet</dt>
<ng-container *ngIf="detailedStaffData.authorisations?.length; else emptyDD"> <ng-container *ngIf="detailedEmployeeData.authorisations?.length; else emptyDD">
<dd *ngFor="let item of detailedStaffData.authorisations"> <dd *ngFor="let item of detailedEmployeeData.authorisations">
{{ item }} {{ item }}
</dd> </dd>
</ng-container> </ng-container>
<dt>Aktivt i arbete</dt> <dt>Aktivt i arbete</dt>
<dd>{{ detailedStaffData.active ? 'Ja' : 'Nej' }}</dd> <dd>{{ detailedEmployeeData.active ? 'Ja' : 'Nej' }}</dd>
<dt>Frånvaroperiod</dt> <dt>Frånvaroperiod</dt>
<ng-container *ngIf="detailedStaffData.outOfOffice?.length; else emptyDD"> <ng-container *ngIf="detailedEmployeeData.outOfOffice?.length; else emptyDD">
<dd *ngFor="let date of detailedStaffData.outOfOffice"> <dd *ngFor="let date of detailedEmployeeData.outOfOffice">
{{ date.start | localDate }} - {{ date.end | localDate }} {{ date.start | localDate }} - {{ date.end | localDate }}
</dd> </dd>
</ng-container> </ng-container>
<dt>Tjänst</dt> <dt>Tjänst</dt>
<dd>{{ detailedStaffData.service || '' }}</dd> <dd>{{ detailedEmployeeData.service || '' }}</dd>
<dt>Språk</dt> <dt>Språk</dt>
<dd>{{ detailedStaffData.languages?.join(', ') }}</dd> <dd>{{ detailedEmployeeData.languages?.join(', ') }}</dd>
</dl> </dl>
</div> </div>
<div class="staff-card__column"> <div class="staff-card__column">
<h2>Utförande verksamhet</h2> <h2>Utförande verksamhet</h2>
<ul *ngIf="detailedStaffData.agencies?.length" class="staff-card__agencies"> <ul *ngIf="detailedEmployeeData.agencies?.length" class="staff-card__agencies">
<li *ngFor="let agency of detailedStaffData.agencies" class="staff-card__agency"> <li *ngFor="let agency of detailedEmployeeData.agencies" class="staff-card__agency">
<h3>{{ agency.name }}</h3> <h3>{{ agency.name }}</h3>
<dl> <dl>
<dt>KA-nummer</dt> <dt>KA-nummer</dt>
@@ -72,23 +72,23 @@
<div class="staff-card__column"> <div class="staff-card__column">
<digi-ng-layout-expansion-panel> <digi-ng-layout-expansion-panel>
<h3 style="margin-bottom: 0" data-slot-trigger> <h3 style="margin-bottom: 0" data-slot-trigger>
Tilldelade deltagare ({{ detailedStaffData.participants?.length || 0 }}) Tilldelade deltagare ({{ detailedEmployeeData.participants?.length || 0 }})
</h3> </h3>
<ng-container *ngIf="detailedStaffData.participants?.length; else noParticipantsInfo"> <ng-container *ngIf="detailedEmployeeData.participants?.length; else noParticipantsInfo">
<ul class="staff-card__participants"> <ul class="staff-card__participants">
<li *ngIf="detailedStaffData.participants.length > 1" class="staff-card__participant"> <li *ngIf="detailedEmployeeData.participants.length > 1" class="staff-card__participant">
<digi-form-checkbox <digi-form-checkbox
af-variation="primary" af-variation="primary"
af-label="Välj alla" af-label="Välj alla"
af-value="all" af-value="all"
[afChecked]="pendingSelectedParticipants.length" [afChecked]="pendingSelectedParticipants.length"
[afIndeterminate]="pendingSelectedParticipants.length !== detailedStaffData.participants.length" [afIndeterminate]="pendingSelectedParticipants.length !== detailedEmployeeData.participants.length"
(afOnChange)=" (afOnChange)="
handleChangeAllParticipants(detailedStaffData.participants, $event.detail.target.checked) handleChangeAllParticipants(detailedEmployeeData.participants, $event.detail.target.checked)
" "
></digi-form-checkbox> ></digi-form-checkbox>
</li> </li>
<li *ngFor="let participant of detailedStaffData.participants" class="staff-card__participant"> <li *ngFor="let participant of detailedEmployeeData.participants" class="staff-card__participant">
<digi-form-checkbox <digi-form-checkbox
af-variation="primary" af-variation="primary"
[afLabel]="participant.fullName" [afLabel]="participant.fullName"
@@ -99,10 +99,10 @@
</li> </li>
</ul> </ul>
<digi-button af-size="s" (afOnClick)="handleChangeStaff()">Byt handledare</digi-button> <digi-button af-size="s" (afOnClick)="handleChangeEmployee()">Byt handledare</digi-button>
</ng-container> </ng-container>
<ng-template #noParticipantsInfo> <ng-template #noParticipantsInfo>
<p>Inga deltagare har kopplats till {{ detailedStaffData.fullName }}.</p> <p>Inga deltagare har kopplats till {{ detailedEmployeeData.fullName }}.</p>
</ng-template> </ng-template>
</digi-ng-layout-expansion-panel> </digi-ng-layout-expansion-panel>
</div> </div>
@@ -1,7 +1,7 @@
@import 'variables/gutters'; @import 'variables/gutters';
@import 'mixins/list'; @import 'mixins/list';
.staff-card { .employee-card {
&__contents { &__contents {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -1,22 +1,22 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { StaffCardComponent } from './staff-card.component'; import { EmployeeCardComponent } from './employee-card.component';
describe('StaffCardComponent', () => { describe('EmployeeCardComponent', () => {
let component: StaffCardComponent; let component: EmployeeCardComponent;
let fixture: ComponentFixture<StaffCardComponent>; let fixture: ComponentFixture<EmployeeCardComponent>;
beforeEach( beforeEach(
waitForAsync(() => { waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [StaffCardComponent], declarations: [EmployeeCardComponent],
imports: [RouterTestingModule], imports: [RouterTestingModule],
}).compileComponents(); }).compileComponents();
}) })
); );
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(StaffCardComponent); fixture = TestBed.createComponent(EmployeeCardComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -1,28 +1,28 @@
import { ChangeDetectionStrategy, Component } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive'; import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive';
import { Employee } from '@dafa-models/employee.model';
import { Participant } from '@dafa-models/participant.model'; import { Participant } from '@dafa-models/participant.model';
import { Staff } from '@dafa-models/staff.model'; import { EmployeeService } from '@dafa-services/api/employee.service';
import { StaffService } from '@dafa-services/api/staff.service';
import { BehaviorSubject, Observable } from 'rxjs'; import { BehaviorSubject, Observable } from 'rxjs';
@Component({ @Component({
selector: 'dafa-staff-card', selector: 'dafa-employee-card',
templateUrl: './staff-card.component.html', templateUrl: './employee-card.component.html',
styleUrls: ['./staff-card.component.scss'], styleUrls: ['./employee-card.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class StaffCardComponent extends UnsubscribeDirective { export class EmployeeCardComponent extends UnsubscribeDirective {
detailedStaffData$: Observable<Staff>; detailedEmployeeData$: Observable<Employee>;
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]); private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
constructor(private activatedRoute: ActivatedRoute, private staffService: StaffService) { constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
super(); super();
super.unsubscribeOnDestroy( super.unsubscribeOnDestroy(
this.activatedRoute.params.subscribe(({ id }) => { this.activatedRoute.params.subscribe(({ id }) => {
console.log(id); console.log(id);
this.detailedStaffData$ = this.staffService.getDetailedStaffData(id); this.detailedEmployeeData$ = this.employeeService.getDetailedEmployeeData(id);
}), }),
this._pendingSelectedParticipants$.subscribe(ids => console.log(ids)) this._pendingSelectedParticipants$.subscribe(ids => console.log(ids))
); );
@@ -32,8 +32,8 @@ export class StaffCardComponent extends UnsubscribeDirective {
return this._pendingSelectedParticipants$.getValue(); return this._pendingSelectedParticipants$.getValue();
} }
handleChangeStaff(): void { handleChangeEmployee(): void {
console.log('change staff: ', this.pendingSelectedParticipants); console.log('change employee: ', this.pendingSelectedParticipants);
} }
handleChangeParticipant(id: string, checked: boolean): void { handleChangeParticipant(id: string, checked: boolean): void {
@@ -4,17 +4,17 @@ import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module'; import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
import { StaffCardComponent } from './staff-card.component'; import { EmployeeCardComponent } from './employee-card.component';
@NgModule({ @NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [StaffCardComponent], declarations: [EmployeeCardComponent],
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{ path: '', component: StaffCardComponent }]), RouterModule.forChild([{ path: '', component: EmployeeCardComponent }]),
DigiNgSkeletonBaseModule, DigiNgSkeletonBaseModule,
DigiNgLayoutExpansionPanelModule, DigiNgLayoutExpansionPanelModule,
LocalDatePipeModule, LocalDatePipeModule,
], ],
}) })
export class StaffCardModule {} export class EmployeeCardModule {}
@@ -0,0 +1,58 @@
<div class="employees-list">
<digi-table af-variation="secondary">
<table>
<thead>
<tr>
<th scope="col" class="employees-list__column-head">
<button class="employees-list__sort-button" (click)="handleSort('fullName')">
Namn
<ng-container *ngIf="sortBy?.key === 'fullName'">
<digi-icon-caret-up class="employees-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
<digi-icon-caret-down class="employees-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="employees-list__column-head">
<button class="employees-list__sort-button" (click)="handleSort('service')">
Tjänst
<ng-container *ngIf="sortBy?.key === 'service'">
<digi-icon-caret-up class="employees-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
<digi-icon-caret-down class="employees-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="employees-list__column-head">
<button class="employees-list__sort-button" (click)="handleSort('utforandeverksamhet')">
Utförandeverksamhet
<ng-container *ngIf="sortBy?.key === 'utforandeverksamhet'">
<digi-icon-caret-up class="employees-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
<digi-icon-caret-down class="employees-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employees of pagedEmployees">
<th scope="row">
<a [routerLink]="employees.id" class="employees-list__link">{{ employees.fullName }}</a>
</th>
<td>{{ employees.service }}</td>
<td>{{ employees.kommun }}</td>
</tr>
</tbody>
</table>
</digi-table>
<digi-navigation-pagination
*ngIf="employees.length > pagedEmployees.length"
class="employees-list__pagination"
[afTotalPages]="totalPages"
[afCurrentResultStart]="currentResultStart"
[afCurrentResultEnd]="currentResultEnd"
[afTotalResults]="employees.length"
(afOnPageChange)="handlePagination($event.detail)"
af-result-name="deltagare"
>
</digi-navigation-pagination>
</div>
@@ -1,6 +1,6 @@
@import 'variables/gutters'; @import 'variables/gutters';
.staff-list { .employees-list {
&__column-head { &__column-head {
padding: 0; padding: 0;
} }
@@ -1,23 +1,23 @@
import { DigiNgTableModule } from '@af/digi-ng/_table/table'; import { DigiNgTableModule } from '@af/digi-ng/_table/table';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { StaffListComponent } from './staff-list.component'; import { EmployeesListComponent } from './employees-list.component';
describe('StaffListComponent', () => { describe('EmployeesListComponent', () => {
let component: StaffListComponent; let component: EmployeesListComponent;
let fixture: ComponentFixture<StaffListComponent>; let fixture: ComponentFixture<EmployeesListComponent>;
beforeEach(async () => { beforeEach(async () => {
await TestBed.configureTestingModule({ await TestBed.configureTestingModule({
declarations: [StaffListComponent], declarations: [EmployeesListComponent],
imports: [RouterTestingModule, DigiNgTableModule], imports: [RouterTestingModule, DigiNgTableModule],
}).compileComponents(); }).compileComponents();
}); });
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(StaffListComponent); fixture = TestBed.createComponent(EmployeesListComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
component.staff = []; component.employees = [];
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -1,21 +1,21 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Employee } from '@dafa-models/employee.model';
import { SortBy } from '@dafa-models/sort-by.model'; import { SortBy } from '@dafa-models/sort-by.model';
import { Staff } from '@dafa-models/staff.model';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
@Component({ @Component({
selector: 'dafa-staff-list', selector: 'dafa-employees-list',
templateUrl: './staff-list.component.html', templateUrl: './employees-list.component.html',
styleUrls: ['./staff-list.component.scss'], styleUrls: ['./employees-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class StaffListComponent { export class EmployeesListComponent {
@Input() staff: Staff[]; @Input() employees: Employee[];
@Input() sortBy: SortBy | null; @Input() sortBy: SortBy | null;
@Output() sorted = new EventEmitter<keyof Staff>(); @Output() sorted = new EventEmitter<keyof Employee>();
private _currentPage$ = new BehaviorSubject<number>(1); private _currentPage$ = new BehaviorSubject<number>(1);
private _staffPerPage = 10; private _employeesPerPage = 10;
private _searchValue$ = new BehaviorSubject<string>(''); private _searchValue$ = new BehaviorSubject<string>('');
@@ -24,22 +24,22 @@ export class StaffListComponent {
} }
get totalPages(): number { get totalPages(): number {
return Math.ceil(this.staff.length / this._staffPerPage); return Math.ceil(this.employees.length / this._employeesPerPage);
} }
get pagedStaff(): Staff[] { get pagedEmployees(): Employee[] {
return [...this.staff].slice(this.currentResultStart - 1, this.currentResultEnd - 1); return [...this.employees].slice(this.currentResultStart - 1, this.currentResultEnd - 1);
} }
get currentResultStart(): number { get currentResultStart(): number {
return (this.currentPage - 1) * this._staffPerPage + 1; return (this.currentPage - 1) * this._employeesPerPage + 1;
} }
get currentResultEnd(): number { get currentResultEnd(): number {
return this.currentResultStart + this._staffPerPage; return this.currentResultStart + this._employeesPerPage;
} }
handleSort(key: keyof Staff): void { handleSort(key: keyof Employee): void {
this.sorted.emit(key); this.sorted.emit(key);
} }
@@ -2,13 +2,12 @@ import { DigiNgTableModule } from '@af/digi-ng/_table/table';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router'; import { RouterModule } from '@angular/router';
import { StaffListComponent } from './staff-list.component'; import { EmployeesListComponent } from './employees-list.component';
@NgModule({ @NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [StaffListComponent], declarations: [EmployeesListComponent],
imports: [CommonModule, RouterModule, DigiNgTableModule], imports: [CommonModule, RouterModule, DigiNgTableModule],
exports: [StaffListComponent], exports: [EmployeesListComponent],
}) })
export class StaffListModule {} export class EmployeesListModule {}
@@ -1,4 +1,4 @@
<section class="staff"> <section class="employees">
<digi-typography> <digi-typography>
<h1>Personal</h1> <h1>Personal</h1>
<p> <p>
@@ -7,13 +7,13 @@
leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est. leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est.
</p> </p>
<div class="staff__cta-wrapper"> <div class="employees__cta-wrapper">
<digi-ng-link-button afText="Skapa nytt konto" afRoute="/administration/skapa-konto"></digi-ng-link-button> <digi-ng-link-button afText="Skapa nytt konto" afRoute="/administration/skapa-konto"></digi-ng-link-button>
</div> </div>
<h2>Personallista</h2> <h2>Personallista</h2>
<form class="staff__search-wrapper" (ngSubmit)="handleSearchSubmit()"> <form class="employees__search-wrapper" (ngSubmit)="handleSearchSubmit()">
<digi-form-input-search <digi-form-input-search
af-label="Sök kunder" af-label="Sök kunder"
af-label-description="Sök på namn eller ärendenummer" af-label-description="Sök på namn eller ärendenummer"
@@ -21,12 +21,12 @@
></digi-form-input-search> ></digi-form-input-search>
</form> </form>
<dafa-staff-list <dafa-employees-list
*ngIf="filteredStaff$ | async as staff; else loadingRef" *ngIf="filteredEmployees$ | async as employees; else loadingRef"
[staff]="staff" [employees]="employees"
[sortBy]="staffSortBy$ | async" [sortBy]="employeesSortBy$ | async"
(sorted)="handleStaffSort($event)" (sorted)="handleEmployeesSort($event)"
></dafa-staff-list> ></dafa-employees-list>
</digi-typography> </digi-typography>
<ng-template #loadingRef> <ng-template #loadingRef>
@@ -1,5 +1,6 @@
@import 'variables/gutters'; @import 'variables/gutters';
.staff {
.employees {
&__cta-wrapper { &__cta-wrapper {
margin-top: var(--digi--layout--gutter); margin-top: var(--digi--layout--gutter);
} }
@@ -1,22 +1,22 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { StaffComponent } from './staff.component'; import { EmployeesComponent } from './employees.component';
describe('StaffComponent', () => { describe('EmployeesComponent', () => {
let component: StaffComponent; let component: EmployeesComponent;
let fixture: ComponentFixture<StaffComponent>; let fixture: ComponentFixture<EmployeesComponent>;
beforeEach( beforeEach(
waitForAsync(() => { waitForAsync(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [StaffComponent], declarations: [EmployeesComponent],
imports: [RouterTestingModule], imports: [RouterTestingModule],
}).compileComponents(); }).compileComponents();
}) })
); );
beforeEach(() => { beforeEach(() => {
fixture = TestBed.createComponent(StaffComponent); fixture = TestBed.createComponent(EmployeesComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
}); });
@@ -0,0 +1,37 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IconType } from '@dafa-enums/icon-type.enum';
import { Employee } from '@dafa-models/employee.model';
import { SortBy } from '@dafa-models/sort-by.model';
import { EmployeeService } from '@dafa-services/api/employee.service';
import { BehaviorSubject, Observable } from 'rxjs';
@Component({
selector: 'dafa-employees',
templateUrl: './employees.component.html',
styleUrls: ['./employees.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EmployeesComponent {
private _searchValue$ = new BehaviorSubject<string>('');
filteredEmployees$: Observable<Employee[]> = this.employeeService.filteredEmployees$;
employeesSortBy$: Observable<SortBy | null> = this.employeeService.employeesSortBy$;
iconType = IconType;
constructor(private employeeService: EmployeeService) {}
get searchValue(): string {
return this._searchValue$.getValue();
}
handleSearchSubmit(): void {
this.employeeService.setSearchFilter(this.searchValue);
}
handleSearchInput($event: CustomEvent): void {
this._searchValue$.next($event.detail.target.value);
}
handleEmployeesSort(key: keyof Employee): void {
this.employeeService.setEmployeesSortKey(key);
}
}
@@ -1,24 +1,24 @@
import { DigiNgLinkButtonModule } from '@af/digi-ng/_link/link-button';
import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal'; import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal';
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base'; import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { StaffListModule } from './components/staff-list/staff-list.module';
import { StaffComponent } from './staff.component';
import { DigiNgLinkButtonModule } from '@af/digi-ng/_link/link-button';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { EmployeesListModule } from './components/employees-list/employees-list.module';
import { EmployeesComponent } from './employees.component';
@NgModule({ @NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA], schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [StaffComponent], declarations: [EmployeesComponent],
imports: [ imports: [
CommonModule, CommonModule,
RouterModule.forChild([{ path: '', component: StaffComponent }]), RouterModule.forChild([{ path: '', component: EmployeesComponent }]),
DigiNgLinkInternalModule, DigiNgLinkInternalModule,
DigiNgSkeletonBaseModule, DigiNgSkeletonBaseModule,
StaffListModule, EmployeesListModule,
DigiNgLinkButtonModule, DigiNgLinkButtonModule,
FormsModule, FormsModule,
], ],
}) })
export class StaffModule {} export class EmployeesModule {}
@@ -1,56 +0,0 @@
<digi-table af-variation="secondary">
<table>
<thead>
<tr>
<th scope="col" class="staff-list__column-head">
<button class="staff-list__sort-button" (click)="handleSort('fullName')">
Namn
<ng-container *ngIf="sortBy?.key === 'fullName'">
<digi-icon-caret-up class="staff-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
<digi-icon-caret-down class="staff-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="staff-list__column-head">
<button class="staff-list__sort-button" (click)="handleSort('service')">
Tjänst
<ng-container *ngIf="sortBy?.key === 'service'">
<digi-icon-caret-up class="staff-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
<digi-icon-caret-down class="staff-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="staff-list__column-head">
<button class="staff-list__sort-button" (click)="handleSort('utforandeverksamhet')">
Utförandeverksamhet
<ng-container *ngIf="sortBy?.key === 'utforandeverksamhet'">
<digi-icon-caret-up class="staff-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
<digi-icon-caret-down class="staff-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let staff of pagedStaff">
<th scope="row">
<a [routerLink]="staff.id" class="staff-list__link">{{ staff.fullName }}</a>
</th>
<td>{{ staff.service }}</td>
<td>{{ staff.kommun }}</td>
</tr>
</tbody>
</table>
</digi-table>
<digi-navigation-pagination
*ngIf="staff.length > pagedStaff.length"
class="staff-list__pagination"
[afTotalPages]="totalPages"
[afCurrentResultStart]="currentResultStart"
[afCurrentResultEnd]="currentResultEnd"
[afTotalResults]="staff.length"
(afOnPageChange)="handlePagination($event.detail)"
af-result-name="deltagare"
>
</digi-navigation-pagination>
@@ -1,37 +0,0 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IconType } from '@dafa-enums/icon-type.enum';
import { SortBy } from '@dafa-models/sort-by.model';
import { Staff } from '@dafa-models/staff.model';
import { StaffService } from '@dafa-services/api/staff.service';
import { BehaviorSubject, Observable } from 'rxjs';
@Component({
selector: 'dafa-staff',
templateUrl: './staff.component.html',
styleUrls: ['./staff.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class StaffComponent {
private _searchValue$ = new BehaviorSubject<string>('');
filteredStaff$: Observable<Staff[]> = this.staffService.filteredStaff$;
staffSortBy$: Observable<SortBy | null> = this.staffService.staffSortBy$;
iconType = IconType;
constructor(private staffService: StaffService) {}
get searchValue(): string {
return this._searchValue$.getValue();
}
handleSearchSubmit(): void {
this.staffService.setSearchFilter(this.searchValue);
}
handleSearchInput($event: CustomEvent): void {
this._searchValue$.next($event.detail.target.value);
}
handleStaffSort(key: keyof Staff): void {
this.staffService.setStaffSortKey(key);
}
}
@@ -0,0 +1,69 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@dafa-environment';
import { Employee, EmployeeDetail } from '@dafa-models/employee.model';
import { SortBy } from '@dafa-models/sort-by.model';
import { sort } from '@dafa-utils/sort.util';
import { BehaviorSubject, combineLatest, Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
function filterEmployees(employees: Employee[], searchFilter: string): Employee[] {
return employees.filter(person => {
const searchValueExistsInName = person.fullName.toLowerCase().includes(searchFilter.toLowerCase());
return searchValueExistsInName;
});
}
@Injectable({
providedIn: 'root',
})
export class EmployeeService {
private _employeesApiUrl = `${environment.apiBase}/employees`;
private _allEmployees$: Observable<Employee[]> = this.httpClient.get<Employee[]>(this._employeesApiUrl, {
params: { _embed: 'participants' },
});
private _employeesSortBy$ = new BehaviorSubject<SortBy | null>({ key: 'fullName', reverse: false });
public employeesSortBy$: Observable<SortBy> = this._employeesSortBy$.asObservable();
private _searchFilter$ = new BehaviorSubject<string>('');
public searchFilter$: Observable<string> = this._searchFilter$.asObservable();
private _filteredEmployees$: Observable<Employee[]> = combineLatest([this._allEmployees$, this._searchFilter$]).pipe(
map(([employees, searchFilter]) => filterEmployees(employees, searchFilter))
);
public filteredEmployees$: Observable<Employee[]> = combineLatest([
this._filteredEmployees$,
this._employeesSortBy$,
]).pipe(
map(([employees, sortBy]) => {
return sortBy ? sort(employees, sortBy) : employees;
})
);
constructor(private httpClient: HttpClient) {}
public getDetailedEmployeeData(id: string): Observable<Employee> {
return this.httpClient.get<Employee>(`${this._employeesApiUrl}/${id}`, { params: { _embed: 'participants' } });
}
public setSearchFilter(value: string) {
this._searchFilter$.next(value);
}
public setEmployeesSortKey(key: keyof Employee) {
const currentSortBy = this._employeesSortBy$.getValue();
const reverse = currentSortBy?.key === key ? !currentSortBy.reverse : false;
this._employeesSortBy$.next({ key, reverse });
}
public createAccount(employeesData: EmployeeDetail): Observable<string> {
return this.httpClient.post<EmployeeDetail>(this._employeesApiUrl, employeesData).pipe(
map(data => data.id),
catchError(error => {
return throwError(error);
})
);
}
}
@@ -1,66 +0,0 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@dafa-environment';
import { SortBy } from '@dafa-models/sort-by.model';
import { Staff, StaffDetail } from '@dafa-models/staff.model';
import { sort } from '@dafa-utils/sort.util';
import { BehaviorSubject, combineLatest, Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
function filterStaff(staff: Staff[], searchFilter: string): Staff[] {
return staff.filter(person => {
const searchValueExistsInName = person.fullName.toLowerCase().includes(searchFilter.toLowerCase());
return searchValueExistsInName;
});
}
@Injectable({
providedIn: 'root',
})
export class StaffService {
private _staffApiUrl = `${environment.apiBase}/staff`;
private _allStaff$: Observable<Staff[]> = this.httpClient.get<Staff[]>(this._staffApiUrl, {
params: { _embed: 'participants' },
});
private _staffSortBy$ = new BehaviorSubject<SortBy | null>({ key: 'fullName', reverse: false });
public staffSortBy$: Observable<SortBy> = this._staffSortBy$.asObservable();
private _searchFilter$ = new BehaviorSubject<string>('');
public searchFilter$: Observable<string> = this._searchFilter$.asObservable();
private _filteredStaff$: Observable<Staff[]> = combineLatest([this._allStaff$, this._searchFilter$]).pipe(
map(([staff, searchFilter]) => filterStaff(staff, searchFilter))
);
public filteredStaff$: Observable<Staff[]> = combineLatest([this._filteredStaff$, this._staffSortBy$]).pipe(
map(([staff, sortBy]) => {
return sortBy ? sort(staff, sortBy) : staff;
})
);
constructor(private httpClient: HttpClient) {}
public getDetailedStaffData(id: string): Observable<Staff> {
return this.httpClient.get<Staff>(`${this._staffApiUrl}/${id}`, { params: { _embed: 'participants' } });
}
public setSearchFilter(value: string) {
this._searchFilter$.next(value);
}
public setStaffSortKey(key: keyof Staff) {
const currentSortBy = this._staffSortBy$.getValue();
const reverse = currentSortBy?.key === key ? !currentSortBy.reverse : false;
this._staffSortBy$.next({ key, reverse });
}
public createAccount(staffData: StaffDetail): Observable<string> {
return this.httpClient.post<StaffDetail>(this._staffApiUrl, staffData).pipe(
map(data => data.id),
catchError(error => {
return throwError(error);
})
);
}
}
@@ -13,13 +13,13 @@ export function mapPathsToBreadcrumbs(
})), })),
]; ];
if (isStaffCardRoute(paths)) { if (isEmployeeCardRoute(paths)) {
breadcrumbs[breadcrumbs.length - 1].text = 'Personalkort'; breadcrumbs[breadcrumbs.length - 1].text = 'Personalkort';
} }
return breadcrumbs; return breadcrumbs;
} }
function isStaffCardRoute(paths: string[]): boolean { function isEmployeeCardRoute(paths: string[]): boolean {
return paths.length === 3 && paths[1] === 'personal'; return paths.length === 3 && paths[1] === 'personal';
} }
+2 -2
View File
@@ -1,5 +1,5 @@
{ {
"/api/*": "/$1", "/api/*": "/$1",
"/participants": "/participants?_embed=staff", "/participants": "/participants?_embed=employees",
"/participant/:id": "/participants/:id?_embed=staff" "/participant/:id": "/participants/:id?_embed=employees"
} }
@@ -14,13 +14,13 @@ const STATUSES = [true, false];
const LANGUAGES = languages.generate(); const LANGUAGES = languages.generate();
const AUTHORISATIONS = ['Hantera användare', 'Hantera origisation', 'Hantera ekonomi']; const AUTHORISATIONS = ['Hantera användare', 'Hantera origisation', 'Hantera ekonomi'];
function generateStaff(amount = 10) { function generateEmployees(amount = 10) {
const staff = []; const employees = [];
for (let i = 1; i <= amount; ++i) { for (let i = 1; i <= amount; ++i) {
const person = { const person = {
id: faker.datatype.uuid(), id: faker.datatype.uuid(),
staffId: faker.datatype.number(), employeeId: faker.datatype.number(),
firstName: faker.name.firstName(), firstName: faker.name.firstName(),
lastName: faker.name.lastName(), lastName: faker.name.lastName(),
kommun: KOMMUN[Math.floor(Math.random() * KOMMUN.length)].kommun, kommun: KOMMUN[Math.floor(Math.random() * KOMMUN.length)].kommun,
@@ -50,13 +50,13 @@ function generateStaff(amount = 10) {
agencies: chooseRandom(AGENCIES, faker.datatype.number(3)), agencies: chooseRandom(AGENCIES, faker.datatype.number(3)),
}; };
staff.push({ ...person, fullName: `${person.firstName} ${person.lastName}` }); employees.push({ ...person, fullName: `${person.firstName} ${person.lastName}` });
} }
console.info('Staff generated...'); console.info('Employees generated...');
return staff; return employees;
} }
export default { export default {
generate: generateStaff, generate: generateEmployees,
}; };
+4 -4
View File
@@ -1,22 +1,22 @@
import fs from 'fs'; import fs from 'fs';
import agencies from './agencies.js'; import agencies from './agencies.js';
import employees from './employees.js';
import kommuner from './kommuner.js'; import kommuner from './kommuner.js';
import languages from './languages.js'; import languages from './languages.js';
import participants from './participants.js'; import participants from './participants.js';
import services from './services.js'; import services from './services.js';
import staff from './staff.js';
const generatedStaff = staff.generate(5); const generatedEmployees = employees.generate(5);
const apiData = { const apiData = {
services: services.generate(), services: services.generate(),
languages: languages.generate(), languages: languages.generate(),
staff: generatedStaff, employees: generatedEmployees,
kommuner: kommuner.generate(), kommuner: kommuner.generate(),
agencies: agencies.generate(), agencies: agencies.generate(),
participants: participants.generate(50).map(participant => ({ participants: participants.generate(50).map(participant => ({
...participant, ...participant,
staffId: generatedStaff[Math.floor(Math.random() * generatedStaff.length)].id, employeeId: generatedEmployees[Math.floor(Math.random() * generatedEmployees.length)].id,
})), })),
}; };