feat(deltagare): Matched deltagareinformation page to the design. (TV-269)

Squashed commit of the following:

commit f850837fb7629ca9acbd7e9e9d6b8e3a9b356e6d
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Aug 3 12:42:46 2021 +0200

    Removed some unnecessary null-checks

commit 2817775633dc9ed546c48cfdd2092eafb0679686
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Aug 3 12:20:58 2021 +0200

    Some template changes

commit 9305a1dce85bf177964ec3ad6bb6fe58b7c52332
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Aug 2 15:21:53 2021 +0200

    Added some fixes to layout

commit 69d5847a0f0ff4aa9fac39ef202edecc28bcfe0f
Merge: c06d16d fe89d57
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Aug 2 11:36:45 2021 +0200

    Merged develop and fixed conflicts

commit c06d16debbe933c1c7f7c927c0f0c32034c6f011
Author: panpe <perham.panbehchi@arbetsformedlingen.se>
Date:   Fri Jul 16 12:56:05 2021 +0200

    fixed some small issues such as disability was not caught. Connected this to the swagger backend. But it needs some better null checks

commit c6a933b3bc2658816bbab5c8399a2de9d3a0bc4a
Author: Cecilia Varnava <cecilia.varnava@arbetsformedlingen.se>
Date:   Mon Jul 12 01:12:35 2021 +0200

    TV-269 wip

commit 5e7252d0dbe33ca3aca0e2e82860fa5b799745cc
Author: Cecilia Varnava <cecilia.varnava@arbetsformedlingen.se>
Date:   Mon Jul 12 01:03:47 2021 +0200

    TV-269 Deltagare - mocked workexperiences

commit f50fa65e2e297f7f551be53a2c181983b53119e4
Author: Cecilia Varnava <cecilia.varnava@arbetsformedlingen.se>
Date:   Thu Jul 8 11:15:47 2021 +0200

    TV-269 added tabs style and deltagare data
This commit is contained in:
Erik Tiekstra
2021-08-03 12:49:24 +02:00
parent fe89d57d3f
commit 1d69b4b013
33 changed files with 329 additions and 855 deletions

View File

@@ -57,6 +57,7 @@ export class AvropComponent {
this.avropService.setHandledareState(handledareId); this.avropService.setHandledareState(handledareId);
} }
goToStep1(): void { goToStep1(): void {
this.avropService.goToStep1(); this.avropService.goToStep1();
} }

View File

@@ -1,72 +1,177 @@
<dafa-layout> <dafa-layout>
<section class="deltagare-card"> <section class="deltagare-card">
<digi-typography *ngIf="deltagare$ | async as deltagare; else loadingRef"> <div *ngIf="deltagare$ | async as deltagare; else loadingRef">
<header class="deltagare-card__header"> <digi-typography>
<dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link> <header class="deltagare-card__header">
<h1>{{ deltagare.fullName }}</h1> <dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link>
</header> <h1>Deltagarinformation</h1>
<p> </header>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus accusantium sit, reprehenderit, esse suscipit <digi-navigation-tabs af-aria-label="Deltagarinformation">
quis similique harum est eum eveniet aspernatur delectus magni asperiores porro aliquam voluptate! Architecto, <digi-navigation-tab af-aria-label="Personuppgifter" af-id="deltagare-card-personuppgifter">
perferendis commodi. <div class="deltagare-card__tab-contents">
</p> <div class="deltagare-card__tab-column">
<h2>Personuppgifter</h2>
<pre>{{deltagare | json}}</pre> <dl>
<dt>Namn:</dt>
<div class="deltagare-card__contents"> <dd *ngIf="deltagare.fullName; else emptyDD">{{ deltagare.fullName }}</dd>
<div class="deltagare-card__column"> <dt>Personnummer:</dt>
<h2>Personuppgifter</h2> <dd *ngIf="deltagare.ssn; else emptyDD">
<dafa-hide-text
<dl> symbols="********-****"
<dt>Namn</dt> [changingText]="deltagare.ssn"
<dd *ngIf="deltagare.fullName; else emptyDD">{{ deltagare.fullName }}</dd> ariaLabelType="personnummer"
<dt>Personnummer</dt> ></dafa-hide-text>
<dd *ngIf="deltagare.ssn; else emptyDD">{{ deltagare.ssn }}</dd> </dd>
<dt>Epostadress</dt> <ng-container *ngFor="let address of deltagare.addresses">
<dd *ngIf="deltagare.email; else emptyDD">{{ deltagare.email }}</dd> <dt>{{address.type}}</dt>
<dt>Telefonnummer</dt> <dd>
<ng-container *ngIf="deltagare.phoneNumbers.length; else emptyDD"> <address>
<ng-container *ngFor="let phoneNumber of deltagare.phoneNumbers"> {{ address.street }}<br />
<dd>{{ phoneNumber.type }}: {{phoneNumber.number}}</dd> {{ address.postalCode }} {{ address.city }}
</ng-container> </address>
</ng-container> </dd>
</dl> </ng-container>
<dt>Telefon:</dt>
<h3>Särskilda behov</h3> <ng-container *ngIf="deltagare.phoneNumbers.length; else emptyDD">
<p> <ng-container *ngFor="let phoneNumber of deltagare.phoneNumbers">
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Minus, voluptatum quibusdam repellendus animi, <dd>{{ phoneNumber.type }}: {{phoneNumber.number}}</dd>
quidem, commodi quos porro quia incidunt saepe veritatis voluptatem. Cupiditate, accusamus atque! Illum, </ng-container>
quisquam esse? Omnis, quasi! </ng-container>
</p> <dt>Epostadress:</dt>
</div> <dd *ngIf="deltagare.email; else emptyDD">{{ deltagare.email }}</dd>
</dl>
<div class="deltagare-card__column"> </div>
<h2>Om tjänsten</h2> <div class="deltagare-card__tab-column">
</div> <h2>Särskilda behov</h2>
<dl>
<div class="deltagare-card__column"> <dt>Funktionsnedsättningar:</dt>
<h2>Matchningsuppgifter</h2> <ng-container *ngIf="deltagare.disabilities; else emptyDD">
</div> <dd *ngFor="let disability of deltagare.disabilities">
<span>{{ disability.title }}</span>
<div class="deltagare-card__column"> <digi-ng-popover class="deltagare-card__popover" [afRelativeIconSize]="true"
<h2>Körkortsinformation</h2> >{{ disability.description }}</digi-ng-popover
<dl> >
<dt>Har körkort</dt> </dd>
<dd>{{deltagare.driversLicense.licenses.length ? 'Ja' : 'Nej'}}</dd> </ng-container>
<ng-container *ngIf="deltagare.driversLicense.licenses.length"> </dl>
<dt>Körkortsklasser</dt> <dl>
<dd>{{deltagare.driversLicense.licenses.join(', ')}}</dd> <dt>Tolk:</dt>
<dt>Tillgång till bil</dt> <dd>{{deltagare.translator ? 'Ja ({{deltagare.translator}})' : 'Nej'}}</dd>
<dd>{{deltagare.driversLicense.accessToCar ? 'Ja' : 'Nej'}}</dd> </dl>
</ng-container> </div>
</dl> <div class="deltagare-card__tab-column">
</div> <h2>Om tjänsten</h2>
</div> <dl>
<dt>Tillhörande tjänst:</dt>
<dd *ngIf="deltagare.service; else emptyDD">{{ deltagare.service }}</dd>
<dt>Datum för tjänstens början:</dt>
<dd *ngIf="deltagare.startDate; else emptyDD">{{ deltagare.startDate | localDate }}</dd>
<dt>Datum för tjänstens slut:</dt>
<dd *ngIf="deltagare.endDate; else emptyDD">{{ deltagare.endDate | localDate }}</dd>
<dt>Deltagandefrekvens:</dt>
<dd *ngIf="deltagare.service?.frequency; else emptyDD">{{ deltagare.service.frequency }}</dd>
<dt>Utförande verksamhet:</dt>
<dd *ngIf="deltagare.service?.organisation; else emptyDD">{{ deltagare.service.organisation }}</dd>
<dt>Utförande adress:</dt>
<dd
*ngIf="
deltagare.service?.organisation &&
deltagare.service?.organisation.adress;
else emptyDD
"
>
{{ deltagare.service.organisation.adress }}
</dd>
<dt>Genomförandereferens:</dt>
<dd *ngIf="deltagare.service?.reference; else emptyDD">{{ deltagare.service.reference }}</dd>
</dl>
</div>
</div>
</digi-navigation-tab>
<digi-navigation-tab af-aria-label="Matchningsuppgifter" af-id="deltagare-card-matchningsuppgifter">
<div class="deltagare-card__tab-contents">
<div class="deltagare-card__tab-column">
<h2>Arbetslivserfarenhet</h2>
<dl>
<dt>Arbetsgivare:</dt>
<ng-container *ngIf="firstVisibleWorkExperiences$ | async as firstVisibleWorkExperiences;">
<ng-container *ngIf="firstVisibleWorkExperiences.length; else emptyDD">
<dd *ngFor="let workExperience of firstVisibleWorkExperiences">
<digi-typography-time [afDateTime]="workExperience.dateFrom"></digi-typography-time>
- <digi-typography-time [afDateTime]="workExperience.dateTo"></digi-typography-time><br />
{{ workExperience.employer }}<br />
{{ workExperience.profession }}<br />
{{ workExperience.description }}
</dd>
</ng-container>
</ng-container>
<ng-container *ngIf="hiddenWorkExperiences$ | async as hiddenWorkExperiences">
<digi-ng-layout-expansion-panel
class="deltagare-card__accordion"
[afExpanded]="accordionExpanded"
(click)="toggleAccordionExpanded()"
*ngIf="hiddenWorkExperiences.length"
>
<span class="deltagare-card__accordion-trigger" data-slot-trigger
>{{ accordionExpanded ? 'Dölj' : 'Visa' }} fler arbetsgivare</span
>
<dd *ngFor="let workExperience of hiddenWorkExperiences">
<digi-typography-time [afDateTime]="workExperience.dateFrom"></digi-typography-time> -
<digi-typography-time [afDateTime]="workExperience.dateTo"></digi-typography-time><br />
{{ workExperience.employer }}<br />
{{ workExperience.profession }}<br />
{{ workExperience.description }}
</dd>
</digi-ng-layout-expansion-panel>
</ng-container>
</dl>
</div>
<div class="deltagare-card__tab-column-education">
<h2>Utbildning</h2>
<dl>
<dt>Utbildningar:</dt>
<ng-container *ngIf="deltagare.educations.length; else emptyDD">
<dd *ngFor="let education of deltagare.educations">
<digi-typography-time [afDateTime]="education.dateFrom"></digi-typography-time> -
<digi-typography-time [afDateTime]="education.dateFrom"></digi-typography-time><br />
{{ education.organizer }}<br />
{{ education.education}}<br />
{{ education.description }}
</dd>
</ng-container>
</dl>
<dl>
<dt>Högsta utbildningsnivå:</dt>
<dd *ngIf="deltagare.highestEducation.level; else emptyDD">
{{ deltagare.highestEducation.level.description }}: {{ deltagare.highestEducation.sunKod.description
}}
</dd>
</dl>
<dl>
<dt>Språk jag kan använda på jobbet:</dt>
<dd *ngIf="deltagare.workLanguages.length else emptyDD">{{ deltagare.workLanguages.join(', ')}}</dd>
</dl>
<h2>Körkortsinformation</h2>
<dl>
<dt>Har körkort</dt>
<dd>{{deltagare.driversLicense.licenses ? 'Ja' : 'Nej'}}</dd>
<ng-container *ngIf="deltagare.driversLicense.licenses">
<dt>Körkortsklasser</dt>
<dd>{{deltagare.driversLicense.licenses.join(', ')}}</dd>
<dt>Tillgång till bil</dt>
<dd>{{deltagare.driversLicense.accessToCar ? 'Ja' : 'Nej'}}</dd>
</ng-container>
</dl>
</div>
</div>
</digi-navigation-tab>
</digi-navigation-tabs>
</digi-typography>
<footer class="deltagare-card__footer"> <footer class="deltagare-card__footer">
<dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link> <dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link>
</footer> </footer>
</digi-typography> </div>
</section> </section>
<ng-template #loadingRef> <ng-template #loadingRef>

View File

@@ -1,45 +1,55 @@
@import 'variables/gutters'; @import 'variables/gutters';
.deltagare-card { .deltagare-card {
&__contents { &__tab-contents {
display: flex; display: flex;
flex-direction: column; gap: $digi--layout--gutter--l;
gap: $digi--layout--gutter--xl $digi--layout--gutter--l; margin: 0 $digi--layout--gutter--l;
}
h2 { &__tab-column {
margin-top: 0; width: 50%;
}
dd {
margin: 0 0 var(--digi--layout--gutter--xs);
+ dd {
margin-top: var(--digi--layout--gutter);
} }
} }
&__column {
width: 100%;
max-width: var(--digi--typography--text--max-width);
}
dl {
display: grid;
grid-template-columns: auto 1fr;
gap: 0.5rem 2rem;
}
dt,
dd {
margin: 0;
}
dt { dt {
grid-column: 1;
font-weight: var(--digi--typography--font-weight--semibold); font-weight: var(--digi--typography--font-weight--semibold);
} }
dd { &__accordion {
grid-column: 2; max-width: 80%;
min-width: 250px;
dd:first-of-type {
margin-top: var(--digi--layout--gutter);
}
}
&__accordion-trigger {
font-weight: var(--digi--typography--font-weight--semibold);
}
&__popover {
display: inline-block;
margin-left: var(--digi--layout--gutter--s);
} }
&__header, &__header,
&__footer { &__footer {
display: flex; display: flex;
flex-direction: row-reverse; flex-direction: row-reverse;
align-items: center;
justify-content: space-between; justify-content: space-between;
} }
&__footer {
margin-top: $digi--layout--gutter--l;
}
} }

View File

@@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
import { IconType } from '@dafa-enums/icon-type.enum'; import { IconType } from '@dafa-enums/icon-type.enum';
import { Deltagare } from '@dafa-models/deltagare.model'; import { Deltagare } from '@dafa-models/deltagare.model';
import { WorkExperience } from '@dafa-models/work-experience.model';
import { DeltagareService } from '@dafa-services/api/deltagare.service'; import { DeltagareService } from '@dafa-services/api/deltagare.service';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators'; import { map, switchMap } from 'rxjs/operators';
@@ -19,7 +20,19 @@ export class DeltagareCardComponent {
deltagare$: Observable<Deltagare> = this._deltagareId$.pipe( deltagare$: Observable<Deltagare> = this._deltagareId$.pipe(
switchMap(deltagareId => this.deltagaresService.deltagare$(deltagareId)) switchMap(deltagareId => this.deltagaresService.deltagare$(deltagareId))
); );
firstVisibleWorkExperiences$: Observable<WorkExperience[]> = this.deltagare$.pipe(
map(deltagare => deltagare.workExperiences.slice(0, 2))
);
hiddenWorkExperiences$: Observable<WorkExperience[]> = this.deltagare$.pipe(
map(deltagare => deltagare.workExperiences.slice(2))
);
iconType = IconType; iconType = IconType;
accordionExpanded = false;
constructor(private activatedRoute: ActivatedRoute, private deltagaresService: DeltagareService) {} constructor(private activatedRoute: ActivatedRoute, private deltagaresService: DeltagareService) {}
toggleAccordionExpanded(): void {
this.accordionExpanded = !this.accordionExpanded;
}
} }

View File

@@ -1,10 +1,17 @@
import { DigiNgLayoutExpansionPanelModule } from '@af/digi-ng/_layout/layout-expansion-panel';
import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal'; import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal';
import { DigiNgNavigationTabModule } from '@af/digi-ng/_navigation/navigation-tab';
import { DigiNgNavigationTabsModule } from '@af/digi-ng/_navigation/navigation-tabs';
import { DigiNgPopoverModule } from '@af/digi-ng/_popover/popover';
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 { RouterModule } from '@angular/router';
import { BackLinkModule } from '@dafa-shared/components/back-link/back-link.module'; import { BackLinkModule } from '@dafa-shared/components/back-link/back-link.module';
import { HideTextModule } from '@dafa-shared/components/hide-text/hide-text.module';
import { IconModule } from '@dafa-shared/components/icon/icon.module'; import { IconModule } from '@dafa-shared/components/icon/icon.module';
import { LayoutModule } from '@dafa-shared/components/layout/layout.module'; import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
import { DeltagareCardComponent } from './deltagare-card.component'; import { DeltagareCardComponent } from './deltagare-card.component';
@NgModule({ @NgModule({
@@ -17,6 +24,13 @@ import { DeltagareCardComponent } from './deltagare-card.component';
DigiNgLinkInternalModule, DigiNgLinkInternalModule,
IconModule, IconModule,
BackLinkModule, BackLinkModule,
DigiNgNavigationTabsModule,
DigiNgNavigationTabModule,
DigiNgLayoutExpansionPanelModule,
LocalDatePipeModule,
HideTextModule,
DigiNgSkeletonBaseModule,
DigiNgPopoverModule,
], ],
exports: [DeltagareCardComponent], exports: [DeltagareCardComponent],
}) })

View File

@@ -1,123 +0,0 @@
<digi-table af-variation="secondary">
<table>
<thead>
<tr>
<th scope="col" class="participants-list__column-head">
<button class="participants-list__sort-button" (click)="handleSort('fullName')">
Namn
<ng-container *ngIf="sortBy?.key === 'fullName'">
<digi-icon-caret-up
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'asc'"
></digi-icon-caret-up>
<digi-icon-caret-down
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'desc'"
></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="participants-list__column-head">
<button class="participants-list__sort-button" (click)="handleSort('errandNumber')">
Ärendenummer
<ng-container *ngIf="sortBy?.key === 'errandNumber'">
<digi-icon-caret-up
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'asc'"
></digi-icon-caret-up>
<digi-icon-caret-down
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'desc'"
></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="participants-list__column-head">
<button class="participants-list__sort-button" (click)="handleSort('service')">
Tjänst
<ng-container *ngIf="sortBy?.key === 'service'">
<digi-icon-caret-up
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'asc'"
></digi-icon-caret-up>
<digi-icon-caret-down
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'desc'"
></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="participants-list__column-head">
<button class="participants-list__sort-button" (click)="handleSort('startDate')">
Startdatum
<ng-container *ngIf="sortBy?.key === 'startDate'">
<digi-icon-caret-up
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'asc'"
></digi-icon-caret-up>
<digi-icon-caret-down
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'desc'"
></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="participants-list__column-head">
<button class="participants-list__sort-button" (click)="handleSort('endDate')">
Slutdatum
<ng-container *ngIf="sortBy?.key === 'endDate'">
<digi-icon-caret-up
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'asc'"
></digi-icon-caret-up>
<digi-icon-caret-down
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'desc'"
></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="participants-list__column-head">
<button class="participants-list__sort-button" (click)="handleSort('handleBefore')">
Hantera innan
<ng-container *ngIf="sortBy?.key === 'handleBefore'">
<digi-icon-caret-up
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'asc'"
></digi-icon-caret-up>
<digi-icon-caret-down
class="participants-list__sort-icon"
*ngIf="sortBy.order === 'desc'"
></digi-icon-caret-down>
</ng-container>
</button>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let participant of pagedParticipants">
<th scope="row">
<a [routerLink]="participant.id" class="participants-list__link">
{{ participant.fullName }}
</a>
</th>
<td>{{ participant.errandNumber }}</td>
<td>{{ participant.service }}</td>
<td>{{ participant.startDate | date: 'yyyy-MM-dd' }}</td>
<td>{{ participant.endDate | date: 'yyyy-MM-dd' }}</td>
<td>{{ participant.handleBefore | date: 'yyyy-MM-dd' }}</td>
</tr>
</tbody>
</table>
</digi-table>
<digi-navigation-pagination
*ngIf="participants.length > pagedParticipants.length"
class="participants-list__pagination"
[afTotalPages]="totalPages"
[afCurrentResultStart]="currentResultStart"
[afCurrentResultEnd]="currentResultEnd"
[afTotalResults]="participants.length"
(afOnPageChange)="handlePagination($event.detail)"
af-result-name="deltagare"
></digi-navigation-pagination>

View File

@@ -1,35 +0,0 @@
@import 'variables/gutters';
.participants-list {
&__column-head {
padding: 0;
}
&__sort-button {
position: relative;
background-color: transparent;
border-width: 0;
width: 100%;
text-align: left;
padding: var(--digi--layout--gutter--s) $digi--layout--gutter--l var(--digi--layout--gutter--s)
var(--digi--layout--gutter);
margin: 0;
font-size: inherit;
font-weight: inherit;
display: flex;
align-items: center;
gap: var(--digi--layout--gutter);
cursor: pointer;
}
&__sort-icon {
position: absolute;
display: inline-flex;
right: 0.5rem;
}
&__pagination {
display: block;
margin-top: var(--digi--layout--gutter);
}
}

View File

@@ -1,29 +0,0 @@
import { DigiNgTableModule } from '@af/digi-ng/_table/table';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ParticipantsListComponent } from './participants-list.component';
describe('ParticipantsListComponent', () => {
let component: ParticipantsListComponent;
let fixture: ComponentFixture<ParticipantsListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [ParticipantsListComponent],
imports: [RouterTestingModule, DigiNgTableModule],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ParticipantsListComponent);
component = fixture.componentInstance;
component.participants = [];
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,47 +0,0 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Participant } from '@dafa-models/participant.model';
import { Sort } from '@dafa-models/sort.model';
import { BehaviorSubject } from 'rxjs';
@Component({
selector: 'dafa-participants-list',
templateUrl: './participants-list.component.html',
styleUrls: ['./participants-list.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ParticipantsListComponent {
@Input() participants: Participant[];
@Input() sortBy: Sort<keyof Participant> | null;
@Output() sorted = new EventEmitter<keyof Participant>();
private _currentPage$ = new BehaviorSubject<number>(1);
private _participantsPerPage = 10;
get currentPage(): number {
return this._currentPage$.getValue();
}
get totalPages(): number {
return Math.ceil(this.participants.length / this._participantsPerPage);
}
get pagedParticipants(): Participant[] {
return [...this.participants].slice(this.currentResultStart - 1, this.currentResultEnd - 1);
}
get currentResultStart(): number {
return (this.currentPage - 1) * this._participantsPerPage + 1;
}
get currentResultEnd(): number {
return this.currentResultStart + this._participantsPerPage;
}
handleSort(key: keyof Participant): void {
this.sorted.emit(key);
}
handlePagination(page: number): void {
this._currentPage$.next(page);
}
}

View File

@@ -1,13 +0,0 @@
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 { ParticipantsListComponent } from './participants-list.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [ParticipantsListComponent],
imports: [CommonModule, RouterModule, DigiNgTableModule],
exports: [ParticipantsListComponent],
})
export class ParticipantsListModule {}

View File

@@ -1,202 +0,0 @@
<dafa-layout>
<section class="participant-card">
<div *ngIf="detailedParticipantData$ | async as detailedParticipantData; else loadingRef">
<header class="participant-card__header">
<dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link>
<h1>Deltagarinformation</h1>
</header>
<digi-ng-navigation-tabs afTablistLabel="Deltagarinformation">
<digi-ng-navigation-tab afLabel="Personuppgifter" afId="tab1">
<digi-ng-typography-base>
<div class="participant-card__tab-contents">
<div class="participant-card__tab-column">
<h2>Personuppgifter</h2>
<dl>
<dt>Namn:</dt>
<dd *ngIf="detailedParticipantData.fullName; else emptyDD">{{ detailedParticipantData.fullName }}</dd>
<dt>Personnummer:</dt>
<dd *ngIf="detailedParticipantData.ssn; else emptyDD">
<dafa-hide-text
symbols="********-****"
[changingText]="detailedParticipantData.ssn"
ariaLabelType="personnummer"
></dafa-hide-text>
</dd>
<dt>Folkbokföringsadress:</dt>
<dd *ngIf="detailedParticipantData.address; else emptyDD">
{{ detailedParticipantData.address.street }} + ' ' + {{ detailedParticipantData.address.number }},
{{ detailedParticipantData.address.postalcode }} + ' ' + {{ detailedParticipantData.address.city }}
</dd>
<dt>Postadress:</dt>
<dd *ngIf="detailedParticipantData.postalAddress; else emptyDD">
{{ detailedParticipantData.postalAddress.street }} + ' ' + {{
detailedParticipantData.postalAddress.number }}, {{ detailedParticipantData.postalAddress.postalcode
}} + ' ' + {{ detailedParticipantData.postalAddress.city }}
</dd>
<dt>Telefon:</dt>
<dd *ngIf="detailedParticipantData.phoneMobile; else emptyDD"></dd>
<dd>{{ detailedParticipantData.phoneMobile }}</dd>
<dt>Mailadress:</dt>
<dd *ngIf="detailedParticipantData.email; else emptyDD"></dd>
<dd>{{ detailedParticipantData.email }}</dd>
</dl>
</div>
<div class="participant-card__tab-column">
<h2>Särskilda behov</h2>
<dl>
<dt>Funktionsnedsättningar</dt>
<ng-container *ngIf="detailedParticipantData.disabilities; else emptyDD">
<!--TODO när api klart: disabilities.length-->
<dd *ngFor="let disability of detailedParticipantData.disabilities">
{{ disability.name }} <br />
{{ disability.description }}
</dd>
</ng-container>
</dl>
<dl>
<dt>Tolk</dt>
<dd *ngIf="detailedParticipantData.interpretorLanguage; else noDD">
Ja ( {{ detailedParticipantData.interpretorLanguage }} )
</dd>
<dt>Språkstöd</dt>
<dd *ngIf="detailedParticipantData.supportLanguage; else noDD">
Ja ( {{ detailedParticipantData.supportLanguage }} )
</dd>
</dl>
</div>
<div class="participant-card__tab-column">
<h2>Om tjänsten</h2>
<dl>
<dt>Tillhörande tjänst</dt>
<dd *ngIf="detailedParticipantData.service; else emptyDD">{{ detailedParticipantData.service }}</dd>
<dt>Datum för tjänstens början</dt>
<dd *ngIf="detailedParticipantData.startDate; else emptyDD">
{{ detailedParticipantData.startDate | localDate }}
</dd>
<dt>Datum för tjänstens slut</dt>
<dd *ngIf="detailedParticipantData.endDate; else emptyDD">
{{ detailedParticipantData.endDate | localDate }}
</dd>
<dt>Deltagandefrekvens</dt>
<dd *ngIf="detailedParticipantData.service.frequency; else emptyDD">
{{ detailedParticipantData.service.frequency }}
</dd>
<dt>Utförande verksamhet</dt>
<dd *ngIf="detailedParticipantData.service.organisation; else emptyDD">
{{ detailedParticipantData.service.organisation }}
</dd>
<dt>Utförande adress</dt>
<dd
*ngIf="
detailedParticipantData.service.organisation &&
detailedParticipantData.service.organisation.adress;
else emptyDD
"
>
{{ detailedParticipantData.service.organisation.adress }}
</dd>
<dt>Genomförandereferens</dt>
<dd *ngIf="detailedParticipantData.service.reference; else emptyDD">
{{ detailedParticipantData.service.reference }}
</dd>
</dl>
</div>
</div>
</digi-ng-typography-base>
</digi-ng-navigation-tab>
<digi-ng-navigation-tab afLabel="Matchningsuppgifter" afId="tab2">
<digi-ng-typography-base>
<div class="participant-card__tab-contents">
<div class="participant-card__tab-column">
<h2>Arbetslivserfarenhet</h2>
<dl>
<dt>Arbetsgivare</dt>
<ng-container *ngIf="detailedParticipantData.workExperiences; else emptyDD">
<!--TODO när api finns: workExperiences.length-->
<dd *ngFor="let workExperience of detailedParticipantData.workExperiences; index as i">
<!-- TODO: workExperiences.length. index 0-2-->
{{ workExperience.dateFrom | localDate }} - {{ workExperience.dateTo | localDate }} <br />
{{ workExperience.company }} <br />
{{ workExperience.direction }} <br />
{{ workExperience.description }}
</dd>
</ng-container>
</dl>
<div class="participant-card__employers-expansion">
<digi-ng-layout-expansion-panel [afExpanded]="accordionExpanded" (click)="toggleAccordionExpanded()">
<digi-ng-typography-base
data-slot-trigger
class="participant-card__employers-expansion__trigger-text"
>
{{ accordionExpanded ? 'Dölj' : 'Visa' }} fler arbetsgivare
</digi-ng-typography-base>
<digi-ng-typography-base>
<dl>
<dd *ngFor="let workExperience of detailedParticipantData.workExperiences">
<!-- TODO: workExperiences.length. Från index 3 -->
{{ workExperience.dateFrom | localDate }} - {{ workExperience.dateTo | localDate }} <br />
{{ workExperience.company }} <br />
{{ workExperience.direction }} <br />
{{ workExperience.description }}
</dd>
</dl>
</digi-ng-typography-base>
</digi-ng-layout-expansion-panel>
</div>
</div>
<div class="participant-card__tab-column-education">
<h2>Utbildning</h2>
<dl>
<dt>Utbildningar</dt>
<ng-container *ngIf="detailedParticipantData.educations; else emptyDD">
<!--TODO när api finns: educations.length-->
<dd *ngFor="let education of detailedParticipantData.educations">
{{ education.dateFrom | localDate }} - {{ education.dateTo | localDate }} <br />
{{ education.organizer }} <br />
{{ education.direction }} <br />
{{ education.description }} <br />
</dd>
</ng-container>
</dl>
<dl>
<dt>Högsta utbildningsnivå</dt>
<dd *ngIf="detailedParticipantData.highestEduction; else emptyDD">
{{ detailedParticipantData.highestEduction }}
</dd>
</dl>
<dl>
<dt>Körkortsinformation</dt>
<dd>Innehar körkort ( {{ detailedParticipantData.driversLicenses ? 'Ja' : 'Nej' }} )</dd>
<dd *ngIf="detailedParticipantData.driversLicenses">
<!-- TODO när api finns: .length -->
Körkortsklasser ( {{ detailedParticipantData.driversLicenses.join(', ') }} )<br />
Tillgång till bil ( {{ detailedParticipantData.accessToCar ? 'Ja' : 'Nej' }} )
</dd>
</dl>
</div>
</div>
</digi-ng-typography-base>
</digi-ng-navigation-tab>
</digi-ng-navigation-tabs>
<footer class="participant-card__footer">
<dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link>
</footer>
</div>
</section>
<ng-template #loadingRef>
<digi-ng-skeleton-base [afCount]="3" afText="Laddar deltagarinformation"></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>
<ng-template #noDD>
<dd>
<span>Nej</span>
</dd>
</ng-template>
</dafa-layout>

View File

@@ -1,51 +0,0 @@
@import 'variables/gutters';
.participant-card {
&__tab-contents {
display: flex;
gap: $digi--layout--gutter--xl $digi--layout--gutter--l;
margin-left: $digi--layout--gutter--l;
h2 {
margin-top: $digi--layout--gutter--l;
}
}
&__tab-column {
flex: 1;
max-width: var(--digi--typography--text--max-width);
}
&__tab-column-education {
flex: 2;
}
dl {
display: block;
}
dt,
dd {
margin: 0;
padding-bottom: var(--digi--layout--gutter--xs);
}
dt {
font-weight: var(--digi--typography--font-weight--semibold);
}
&__employers-expansion {
width: 70%;
&__trigger-text {
font-weight: var(--digi--typography--font-weight--bold);
}
}
&__header,
&__footer {
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
}
}

View File

@@ -1,30 +0,0 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { IconType } from '@dafa-enums/icon-type.enum';
import { Participant } from '@dafa-models/participant.model';
import { ParticipantsService } from '@dafa-services/api/participants.service';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
@Component({
selector: 'dafa-participant-card',
templateUrl: './participant-card.component.html',
styleUrls: ['./participant-card.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ParticipantCardComponent {
private _participantId$: Observable<string> = this.activatedRoute.params.pipe(
map(({ participantId }) => participantId as string)
);
detailedParticipantData$: Observable<Participant> = this._participantId$.pipe(
switchMap(participantId => this.participantsService.fetchDetailedParticipantData$(participantId))
);
iconType = IconType;
accordionExpanded = false;
constructor(private activatedRoute: ActivatedRoute, private participantsService: ParticipantsService) {}
toggleAccordionExpanded(): void {
this.accordionExpanded = !this.accordionExpanded;
}
}

View File

@@ -1,35 +0,0 @@
import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { BackLinkModule } from '@dafa-shared/components/back-link/back-link.module';
import { IconModule } from '@dafa-shared/components/icon/icon.module';
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
import { ParticipantCardComponent } from './participant-card.component';
import { HideTextModule } from '@dafa-shared/components/hide-text/hide-text.module';
import { DigiNgNavigationTabsModule } from '@af/digi-ng/_navigation/navigation-tabs';
import { DigiNgNavigationTabModule } from '@af/digi-ng/_navigation/navigation-tab';
import { DigiNgLayoutExpansionPanelModule } from '@af/digi-ng/_layout/layout-expansion-panel';
import { DigiNgTypographyBaseModule } from '@af/digi-ng/_typography/typography-base';
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [ParticipantCardComponent],
imports: [
CommonModule,
RouterModule.forChild([{ path: '', component: ParticipantCardComponent }]),
LayoutModule,
DigiNgLinkInternalModule,
IconModule,
BackLinkModule,
HideTextModule,
DigiNgNavigationTabsModule,
DigiNgNavigationTabModule,
DigiNgLayoutExpansionPanelModule,
DigiNgTypographyBaseModule,
LocalDatePipeModule,
],
exports: [ParticipantCardComponent],
})
export class ParticipantCardModule {}

View File

@@ -1,20 +0,0 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ParticipantsComponent } from './participants.component';
const routes: Routes = [
{
path: '',
component: ParticipantsComponent,
},
{
path: ':participantId',
loadChildren: () => import('./pages/participant-card/participant-card.module').then(m => m.ParticipantCardModule),
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ParticipantsRoutingModule {}

View File

@@ -1,44 +0,0 @@
<dafa-layout>
<section class="participants">
<digi-typography>
<h1>Mina deltagare</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam magna neque, interdum vel massa eget, condimentum
rutrum velit. Sed vitae ullamcorper sem. Aliquam malesuada nunc sed purus mollis scelerisque. Curabitur bibendum
leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est.
</p>
</digi-typography>
<form class="participants__search-wrapper" (ngSubmit)="handleSearchSubmit()">
<digi-form-input-search
af-label="Sök deltagare"
af-label-description="Sök på namn eller ärendenummer"
(afOnInput)="handleSearchInput($event)"
></digi-form-input-search>
</form>
<section class="participants__list">
<h2>Pågående tjänst</h2>
<dafa-participants-list
*ngIf="activeParticipants$ | async as participants; else loadingRef"
[participants]="participants"
[sortBy]="activeParticipantsSortBy$ | async"
(sorted)="handleActiveParticipantsSort($event)"
></dafa-participants-list>
</section>
<section class="participants__list">
<h2>För uppföljning</h2>
<dafa-participants-list
*ngIf="followUpParticipants$ | async as participants; else loadingRef"
[participants]="participants"
[sortBy]="followUpParticipantsSortBy$ | async"
(sorted)="handleFollowUpParticipantsSort($event)"
></dafa-participants-list>
</section>
<ng-template #loadingRef>
<digi-ng-skeleton-base [afCount]="3" afText="Laddar deltagare"></digi-ng-skeleton-base>
</ng-template>
</section>
</dafa-layout>

View File

@@ -1,9 +0,0 @@
@import 'variables/gutters';
.participants {
&__search-wrapper {
max-width: var(--digi--typography--text--max-width);
margin-top: $digi--layout--gutter--l;
margin-bottom: $digi--layout--gutter--xl;
}
}

View File

@@ -1,32 +0,0 @@
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { ParticipantsListModule } from './components/participants-list/participants-list.module';
import { ParticipantsComponent } from './participants.component';
describe('ParticipantsComponent', () => {
let component: ParticipantsComponent;
let fixture: ComponentFixture<ParticipantsComponent>;
beforeEach(
waitForAsync(() => {
void TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [ParticipantsComponent],
imports: [RouterTestingModule, HttpClientTestingModule, DigiNgSkeletonBaseModule, ParticipantsListModule],
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(ParticipantsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -1,44 +0,0 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Participant } from '@dafa-models/participant.model';
import { Sort } from '@dafa-models/sort.model';
import { ParticipantsService } from '@dafa-services/api/participants.service';
import { BehaviorSubject, Observable } from 'rxjs';
@Component({
selector: 'dafa-participants',
templateUrl: './participants.component.html',
styleUrls: ['./participants.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ParticipantsComponent {
private _searchValue$ = new BehaviorSubject<string>('');
activeParticipants$: Observable<Participant[]> = this.participantsService.activeParticipants$;
followUpParticipants$: Observable<Participant[]> = this.participantsService.followUpParticipants$;
activeParticipantsSortBy$: Observable<Sort<keyof Participant> | null> = this.participantsService
.activeParticipantsSortBy$;
followUpParticipantsSortBy$: Observable<Sort<keyof Participant> | null> = this.participantsService
.followUpParticipantsSortBy$;
constructor(private participantsService: ParticipantsService) {}
get searchValue(): string {
return this._searchValue$.getValue();
}
handleSearchSubmit(): void {
this.participantsService.setSearchFilter(this.searchValue);
}
handleSearchInput($event: CustomEvent): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
this._searchValue$.next($event.detail.target.value);
}
handleActiveParticipantsSort(key: keyof Participant): void {
this.participantsService.setActiveParticipantsSortKey(key);
}
handleFollowUpParticipantsSort(key: keyof Participant): void {
this.participantsService.setFollowUpParticipantsSortKey(key);
}
}

View File

@@ -1,22 +0,0 @@
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
import { ParticipantsListModule } from './components/participants-list/participants-list.module';
import { ParticipantsRoutingModule } from './participants-routing.module';
import { ParticipantsComponent } from './participants.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [ParticipantsComponent],
imports: [
CommonModule,
LayoutModule,
ParticipantsRoutingModule,
FormsModule,
DigiNgSkeletonBaseModule,
ParticipantsListModule,
],
})
export class ParticipantsModule {}

View File

@@ -4,6 +4,7 @@ import { DriversLicenseResponse } from './drivers-license.response.model';
import { EducationsResponse } from './educations.response.model'; import { EducationsResponse } from './educations.response.model';
import { HighestEducationResponse } from './highest-education.response.model'; import { HighestEducationResponse } from './highest-education.response.model';
import { TranslatorResponse } from './translator.response.model'; import { TranslatorResponse } from './translator.response.model';
import { WorkExperiencesResponse } from './work-experiences.response.model';
import { WorkLanguagesResponse } from './work-languages.response.model'; import { WorkLanguagesResponse } from './work-languages.response.model';
export interface DeltagareResponse { export interface DeltagareResponse {
@@ -15,4 +16,5 @@ export interface DeltagareResponse {
translator: TranslatorResponse; translator: TranslatorResponse;
workLanguages: WorkLanguagesResponse; workLanguages: WorkLanguagesResponse;
disabilities: DisabilitiesResponse; disabilities: DisabilitiesResponse;
workExperiences: WorkExperiencesResponse;
} }

View File

@@ -1,4 +1,5 @@
export interface DisabilityResponse { export interface DisabilityResponse {
kod: string; kod: string;
funktionsnedsattning: string; funktionsnedsattning: string;
beskrivning: string; beskrivning: string;

View File

@@ -6,6 +6,7 @@ import { DriversLicense, mapResponseToDriversLicense } from './drivers-license.m
import { Education, mapResponseToEducation } from './education.model'; import { Education, mapResponseToEducation } from './education.model';
import { HighestEducation, mapResponseToHighestEducation } from './highest-education.model'; import { HighestEducation, mapResponseToHighestEducation } from './highest-education.model';
import { PhoneNumber } from './phonenumber.model'; import { PhoneNumber } from './phonenumber.model';
import { mapResponseToWorkExperience, WorkExperience } from './work-experience.model';
export interface DeltagareCompact { export interface DeltagareCompact {
id: string; id: string;
@@ -25,11 +26,21 @@ export interface Deltagare extends DeltagareCompact {
translator: string; translator: string;
disabilities: Disability[]; disabilities: Disability[];
workLanguages: string[]; workLanguages: string[];
// workExperiences: WorkExperience[]; // TODO: Missing from API workExperiences: WorkExperience[];
} }
export function mapResponseToDeltagare(data: DeltagareResponse): Deltagare { export function mapResponseToDeltagare(data: DeltagareResponse): Deltagare {
const { id, contact, driverlicense, highestEducation, educations, translator, workLanguages, disabilities } = data; const {
id,
contact,
driverlicense,
highestEducation,
educations,
translator,
workLanguages,
disabilities,
workExperiences,
} = data;
return { return {
id, id,
@@ -41,5 +52,8 @@ export function mapResponseToDeltagare(data: DeltagareResponse): Deltagare {
workLanguages: workLanguages && workLanguages.sprak.map(language => language.beskrivning), workLanguages: workLanguages && workLanguages.sprak.map(language => language.beskrivning),
disabilities: disabilities:
disabilities && disabilities.funktionsnedsattningar.map(disability => mapResponseToDisability(disability)), disabilities && disabilities.funktionsnedsattningar.map(disability => mapResponseToDisability(disability)),
workExperiences:
workExperiences &&
workExperiences.arbetslivserfarenheter.map(workExperience => mapResponseToWorkExperience(workExperience)),
}; };
} }

View File

@@ -8,7 +8,6 @@ export interface Disability {
export function mapResponseToDisability(data: DisabilityResponse): Disability { export function mapResponseToDisability(data: DisabilityResponse): Disability {
const { kod, funktionsnedsattning, beskrivning } = data; const { kod, funktionsnedsattning, beskrivning } = data;
return { return {
code: kod, code: kod,
title: funktionsnedsattning, // TODO: Needed from API title: funktionsnedsattning, // TODO: Needed from API

View File

@@ -1,12 +1,12 @@
import { formatToIsoDate } from '@dafa-utils/format-to-iso-date.util'; import { formatToDate } from '@dafa-utils/format-to-date.util';
import { EducationResponse } from './api/education.response.model'; import { EducationResponse } from './api/education.response.model';
export interface Education { export interface Education {
education: string; education: string;
description: string; description: string;
organizer: string; organizer: string;
dateFrom: string; dateFrom: Date;
dateTo: string; dateTo: Date;
} }
export function mapResponseToEducation(data: EducationResponse): Education { export function mapResponseToEducation(data: EducationResponse): Education {
@@ -16,7 +16,7 @@ export function mapResponseToEducation(data: EducationResponse): Education {
education: utbildning, education: utbildning,
description: beskrivning, description: beskrivning,
organizer: anordnare, organizer: anordnare,
dateFrom: formatToIsoDate(period_from), dateFrom: formatToDate(period_from),
dateTo: formatToIsoDate(period_tom), dateTo: formatToDate(period_tom),
}; };
} }

View File

@@ -26,6 +26,7 @@ export interface UserApiResponseData {
export function mapUserApiResponseToUser(data: UserApiResponseData): User { export function mapUserApiResponseToUser(data: UserApiResponseData): User {
const { id, firstName, lastName, ssn, organizations, authorizations } = data; const { id, firstName, lastName, ssn, organizations, authorizations } = data;
return { return {
id, id,
firstName, firstName,

View File

@@ -1,12 +1,12 @@
import { formatToIsoDate } from '@dafa-utils/format-to-iso-date.util'; import { formatToDate } from '@dafa-utils/format-to-date.util';
import { WorkExperienceResponse } from './api/work-experience.response.model'; import { WorkExperienceResponse } from './api/work-experience.response.model';
export interface WorkExperience { export interface WorkExperience {
profession: string; profession: string;
description: string; description: string;
employer: string; employer: string;
dateFrom: string; dateFrom: Date;
dateTo: string; dateTo: Date;
} }
export function mapResponseToWorkExperience(data: WorkExperienceResponse): WorkExperience { export function mapResponseToWorkExperience(data: WorkExperienceResponse): WorkExperience {
@@ -16,7 +16,7 @@ export function mapResponseToWorkExperience(data: WorkExperienceResponse): WorkE
profession: yrke, profession: yrke,
description: beskrivning, description: beskrivning,
employer: arbetsgivare, employer: arbetsgivare,
dateFrom: formatToIsoDate(period_from), dateFrom: formatToDate(period_from),
dateTo: formatToIsoDate(period_tom), dateTo: formatToDate(period_tom),
}; };
} }

View File

@@ -18,7 +18,7 @@ import { Education, mapResponseToEducation } from '@dafa-models/education.model'
import { HighestEducation, mapResponseToHighestEducation } from '@dafa-models/highest-education.model'; import { HighestEducation, mapResponseToHighestEducation } from '@dafa-models/highest-education.model';
import { mapResponseToWorkExperience, WorkExperience } from '@dafa-models/work-experience.model'; import { mapResponseToWorkExperience, WorkExperience } from '@dafa-models/work-experience.model';
import { combineLatest, Observable } from 'rxjs'; import { combineLatest, Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators'; import { map } from 'rxjs/operators';
const API_HEADERS = { headers: environment.api.headers }; const API_HEADERS = { headers: environment.api.headers };
@@ -30,16 +30,10 @@ export class DeltagareService {
private _fetchAllDeltagare: Observable<DeltagareResponse[]> = this.httpClient private _fetchAllDeltagare: Observable<DeltagareResponse[]> = this.httpClient
.get<{ data: DeltagareResponse[] }>(`${this._apiBaseUrl}`, { ...API_HEADERS }) .get<{ data: DeltagareResponse[] }>(`${this._apiBaseUrl}`, { ...API_HEADERS })
.pipe( .pipe(map(response => response.data));
map(response => {
return response.data;
})
);
public allDeltagare$: Observable<Deltagare[]> = this._fetchAllDeltagare.pipe( public allDeltagare$: Observable<Deltagare[]> = this._fetchAllDeltagare.pipe(
map(data => { map(data => data.map(deltagare => mapResponseToDeltagare(deltagare)))
return data.map(deltagare => mapResponseToDeltagare(deltagare));
})
); );
private _fetchContactInformation$(id: string): Observable<ContactInformation> { private _fetchContactInformation$(id: string): Observable<ContactInformation> {
@@ -47,16 +41,19 @@ export class DeltagareService {
.get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/contact/${id}`, { ...API_HEADERS }) .get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/contact/${id}`, { ...API_HEADERS })
.pipe(map(response => mapResponseToContactInformation(response.data))); .pipe(map(response => mapResponseToContactInformation(response.data)));
} }
private _fetchDriversLicense$(id: string): Observable<DriversLicense> { private _fetchDriversLicense$(id: string): Observable<DriversLicense> {
return this.httpClient return this.httpClient
.get<{ data: DriversLicenseResponse }>(`${this._apiBaseUrl}/driverlicense/${id}`, { ...API_HEADERS }) .get<{ data: DriversLicenseResponse }>(`${this._apiBaseUrl}/driverlicense/${id}`, { ...API_HEADERS })
.pipe(map(response => mapResponseToDriversLicense(response.data))); .pipe(map(response => mapResponseToDriversLicense(response.data)));
} }
private _fetchHighestEducation$(id: string): Observable<HighestEducation> { private _fetchHighestEducation$(id: string): Observable<HighestEducation> {
return this.httpClient return this.httpClient
.get<{ data: HighestEducationResponse }>(`${this._apiBaseUrl}/education/highest/${id}`, { ...API_HEADERS }) .get<{ data: HighestEducationResponse }>(`${this._apiBaseUrl}/education/highest/${id}`, { ...API_HEADERS })
.pipe(map(response => mapResponseToHighestEducation(response.data))); .pipe(map(response => mapResponseToHighestEducation(response.data)));
} }
private _fetchEducations$(id: string): Observable<Education[]> { private _fetchEducations$(id: string): Observable<Education[]> {
return this.httpClient return this.httpClient
.get<{ data: EducationsResponse }>(`${this._apiBaseUrl}/education/${id}`, { ...API_HEADERS }) .get<{ data: EducationsResponse }>(`${this._apiBaseUrl}/education/${id}`, { ...API_HEADERS })
@@ -68,21 +65,23 @@ export class DeltagareService {
) )
); );
} }
private _fetchTranslator$(id: string): Observable<string> { private _fetchTranslator$(id: string): Observable<string> {
return this.httpClient return this.httpClient
.get<{ data: TranslatorResponse }>(`${this._apiBaseUrl}/translator/${id}`, { ...API_HEADERS }) .get<{ data: TranslatorResponse }>(`${this._apiBaseUrl}/translator/${id}`, { ...API_HEADERS })
.pipe(map(response => (response.data.sprak ? response.data.sprak.beskrivning : null))); .pipe(map(response => (response.data.sprak ? response.data.sprak.beskrivning : null)));
} }
private _fetchWorkLanguages$(id: string): Observable<string[]> { private _fetchWorkLanguages$(id: string): Observable<string[]> {
return this.httpClient return this.httpClient
.get<{ data: WorkLanguagesResponse }>(`${this._apiBaseUrl}/work/languages/${id}`, { ...API_HEADERS }) .get<{ data: WorkLanguagesResponse }>(`${this._apiBaseUrl}/work/languages/${id}`, { ...API_HEADERS })
.pipe(map(response => (response.data.sprak ? response.data.sprak.map(sprak => sprak.beskrivning) : []))); .pipe(map(response => (response.data.sprak ? response.data.sprak.map(sprak => sprak.beskrivning) : [])));
} }
private _fetchDisabilities$(id: string): Observable<Disability[]> { private _fetchDisabilities$(id: string): Observable<Disability[]> {
return this.httpClient return this.httpClient
.get<DisabilityResponse[][]>(`${this._apiBaseUrl}/work/disability/${id}`, { ...API_HEADERS }) .get<DisabilityResponse[][]>(`${this._apiBaseUrl}/work/disability/${id}`, { ...API_HEADERS })
.pipe( .pipe(
tap(response => console.log(response)),
map(response => map(response =>
response ? response[0].map(funktionsnedsattning => mapResponseToDisability(funktionsnedsattning)) : [] response ? response[0].map(funktionsnedsattning => mapResponseToDisability(funktionsnedsattning)) : []
) )

View File

@@ -1,5 +1,5 @@
// Takes either 6 or 8 characters string (YYYYMMDD) and formats it to ISO standard (YYYY-MM-DD). // Takes either 6 or 8 characters string (YYYYMMDD) and formats it to ISO standard (YYYY-MM-DD).
export function formatToIsoDate(date: string): string { export function formatToIsoString(date: string): string {
if (date.length === 6) { if (date.length === 6) {
return `${date.substring(0, 4)}-${date.substring(4)}`; return `${date.substring(0, 4)}-${date.substring(4)}`;
} else if (date.length === 8) { } else if (date.length === 8) {
@@ -8,3 +8,11 @@ export function formatToIsoDate(date: string): string {
return date; return date;
} }
export function formatToDate(date: string): Date {
const year = date.substring(0, 4);
const month = date.substring(4, 6) || '01';
const day = date.substring(6, 8) || '01';
return new Date(`${year}-${month}-${day}`);
}

View File

@@ -4,6 +4,7 @@ import educationLevels from './education-levels.js';
import languages from './languages.js'; import languages from './languages.js';
import sunKoder from './sun-koder.js'; import sunKoder from './sun-koder.js';
import chooseRandom from './utils/choose-random.util.js'; import chooseRandom from './utils/choose-random.util.js';
import workExperiences from './work-experiences.js';
faker.locale = 'sv'; faker.locale = 'sv';
@@ -12,6 +13,7 @@ const DRIVERS_LICENSES = ['AM', 'A1', 'A2', 'A', 'B', 'BE', 'B96', 'C1', 'C', 'C
const EDUCATION_LEVELS = educationLevels.generate(); const EDUCATION_LEVELS = educationLevels.generate();
const SUN_KODER = sunKoder.generate(); const SUN_KODER = sunKoder.generate();
const DISABILITIES = disabilities.generate(); const DISABILITIES = disabilities.generate();
const WORK_EXPERIENCES = workExperiences.generate();
const EDUCATIONS = [ const EDUCATIONS = [
{ {
utbildning: 'Lingvistik', utbildning: 'Lingvistik',
@@ -107,6 +109,9 @@ function generateDeltagare(amount = 10) {
disabilities: { disabilities: {
funktionsnedsattningar: Math.random() > 0.3 ? chooseRandom(DISABILITIES, faker.datatype.number(3)) : [], funktionsnedsattningar: Math.random() > 0.3 ? chooseRandom(DISABILITIES, faker.datatype.number(3)) : [],
}, },
workExperiences: {
arbetslivserfarenheter: chooseRandom(WORK_EXPERIENCES, faker.datatype.number(WORK_EXPERIENCES.length)),
}
}; };
if (Math.random() > 0.8) { if (Math.random() > 0.8) {
deltagare.contact.adresser.push({ deltagare.contact.adresser.push({

View File

@@ -0,0 +1,38 @@
function generateWorkExperiences() {
console.info('Work experiences generated...');
return [
{
yrke: 'Revisorer m.fl.',
beskrivning: 'asasaf',
arbetsgivare: 'Jobbet AB',
period_from: '20090501',
period_tom: '20110430'
},
{
yrke: 'Revisorer m.fl.',
beskrivning: 'asasaf',
arbetsgivare: 'Himmelsö AB',
period_from: '20130829',
period_tom: '20140128'
},
{
yrke: 'Revisorer m.fl.',
beskrivning: 'asasaf',
arbetsgivare: 'Himmelsö AB',
period_from: '20140129',
period_tom: '20141126'
},
{
yrke: 'Revisorer m.fl.',
beskrivning: 'AFAsdfasdf',
arbetsgivare: 'Distansutbildningsnämnden',
period_from: '20140527',
period_tom: '20141126'
},
];
}
export default {
generate: generateWorkExperiences,
};

14
package-lock.json generated
View File

@@ -21,7 +21,7 @@
"@angular/platform-browser": "^11.2.0", "@angular/platform-browser": "^11.2.0",
"@angular/platform-browser-dynamic": "^11.2.0", "@angular/platform-browser-dynamic": "^11.2.0",
"@angular/router": "^11.2.0", "@angular/router": "^11.2.0",
"@digi/core": "^9.1.0", "@digi/core": "^9.4.0",
"@digi/styles": "^6.0.2", "@digi/styles": "^6.0.2",
"@nrwl/angular": "11.5.1", "@nrwl/angular": "11.5.1",
"date-fns": "^2.22.1", "date-fns": "^2.22.1",
@@ -2716,9 +2716,9 @@
} }
}, },
"node_modules/@digi/core": { "node_modules/@digi/core": {
"version": "9.1.0", "version": "9.4.0",
"resolved": "http://nexus.arbetsformedlingen.se/repository/npm/@digi/core/-/core-9.1.0.tgz", "resolved": "http://nexus.arbetsformedlingen.se/repository/npm/@digi/core/-/core-9.4.0.tgz",
"integrity": "sha512-d2qTtSWPq0XfIwMaTsVIBdD5gnof7kJcUo4mHTGDaoN7tKD624u8CbbhaYaE3BF/0awuDEQkwxYSzuYiprJmUg==", "integrity": "sha512-47n9gPOAatEKMDy5GPH0sM/xHCizPrKnyjxb9zAxeHntSQdqstsTvb5/03gntqxKY8YndpJd2ksPxhU6w1ri5g==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@digi/styles": { "node_modules/@digi/styles": {
@@ -35654,9 +35654,9 @@
} }
}, },
"@digi/core": { "@digi/core": {
"version": "9.1.0", "version": "9.4.0",
"resolved": "http://nexus.arbetsformedlingen.se/repository/npm/@digi/core/-/core-9.1.0.tgz", "resolved": "http://nexus.arbetsformedlingen.se/repository/npm/@digi/core/-/core-9.4.0.tgz",
"integrity": "sha512-d2qTtSWPq0XfIwMaTsVIBdD5gnof7kJcUo4mHTGDaoN7tKD624u8CbbhaYaE3BF/0awuDEQkwxYSzuYiprJmUg==" "integrity": "sha512-47n9gPOAatEKMDy5GPH0sM/xHCizPrKnyjxb9zAxeHntSQdqstsTvb5/03gntqxKY8YndpJd2ksPxhU6w1ri5g=="
}, },
"@digi/styles": { "@digi/styles": {
"version": "6.0.2", "version": "6.0.2",

View File

@@ -53,7 +53,7 @@
"@angular/platform-browser": "^11.2.0", "@angular/platform-browser": "^11.2.0",
"@angular/platform-browser-dynamic": "^11.2.0", "@angular/platform-browser-dynamic": "^11.2.0",
"@angular/router": "^11.2.0", "@angular/router": "^11.2.0",
"@digi/core": "^9.1.0", "@digi/core": "^9.4.0",
"@digi/styles": "^6.0.2", "@digi/styles": "^6.0.2",
"@nrwl/angular": "11.5.1", "@nrwl/angular": "11.5.1",
"date-fns": "^2.22.1", "date-fns": "^2.22.1",