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

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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',

View File

@@ -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]);
}, },

View File

@@ -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>

View File

@@ -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;

View File

@@ -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();
}); });

View File

@@ -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 {

View File

@@ -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 {}

View File

@@ -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>

View File

@@ -1,6 +1,6 @@
@import 'variables/gutters'; @import 'variables/gutters';
.staff-list { .employees-list {
&__column-head { &__column-head {
padding: 0; padding: 0;
} }

View File

@@ -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();
}); });

View File

@@ -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);
} }

View File

@@ -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 {}

View File

@@ -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>

View File

@@ -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);
} }

View File

@@ -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();
}); });

View File

@@ -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);
}
}

View File

@@ -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 {}

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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);
})
);
}
}

View File

@@ -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);
})
);
}
}

View File

@@ -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';
} }

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"
} }

View File

@@ -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,
}; };

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,
})), })),
}; };