feat(deltagare): Added deltagare data and models (TV-268)

Squashed commit of the following:

commit 8b61e3edeb644d7a27d322a569e85a7f76667243
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Jul 2 14:26:13 2021 +0200

    Removed comments

commit 40dd5f0c186ab4b7b239c054d468f33bd550e0a4
Merge: 3a51568 a11d166
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Jul 2 13:00:59 2021 +0200

    Merge branch 'develop' into feature/TV-268-deltagare-data

commit 3a515683513e8152507a744489d79dc62efbc64c
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Jul 2 12:53:03 2021 +0200

    Removed wrong data-structure from deltagare-card component

commit 2b2da9fb6b25c980bacfe3f37201f569c05fce8c
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Jul 2 12:19:37 2021 +0200

    Added more mock-data to deltagare api

commit 8c52ba5a3a259eb0a4c084eb516180a333bafb45
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Jul 2 11:01:47 2021 +0200

    Added highestEducation to mock-api and fixed dynamic mock-api paths

commit a6b372bf05900698dc592ca15853def26cebe841
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Fri Jul 2 08:33:06 2021 +0200

    Added fallbackvalues for deltagare

commit 6bbad6826620fc4d95877884fefbb0951216fab0
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Jul 1 16:05:05 2021 +0200

    WIP adding mock-data

commit b20e3b057ac50c7f929e8eeaff3a06c5372280a9
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Jul 1 10:30:32 2021 +0200

    Added some data to deltagarekort

commit ac15170c089be760bd72a470e9f83603dedba945
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Thu Jul 1 09:40:56 2021 +0200

    Added deltagare page and components. Also mapped drivers-licenses

commit 80785b31453553ce78e75b8a76a9ca2758870a0e
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Jun 30 15:52:28 2021 +0200

    Added mapping

commit 1b15d0d621b2bb0b3d44d695df12f68637205223
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Jun 30 15:20:53 2021 +0200

    Added deltagareCompact in service

commit 20f7de869d0343a5af59acb83964eea224bcf926
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Wed Jun 30 14:57:59 2021 +0200

    Added deltagare models and started with service
This commit is contained in:
Erik Tiekstra
2021-07-02 14:32:37 +02:00
parent 07ce7a4493
commit c4ffb2aeb3
53 changed files with 2115 additions and 448 deletions

View File

@@ -19,7 +19,7 @@ const routes: Routes = [
{
path: 'deltagare',
data: { title: 'Deltagare' },
loadChildren: () => import('./pages/participants/participants.module').then(m => m.ParticipantsModule),
loadChildren: () => import('./pages/deltagare/deltagare.module').then(m => m.DeltagareModule),
canActivate: [AuthGuard],
},
{

View File

@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DeltagareComponent } from './deltagare.component';
const routes: Routes = [
{
path: '',
component: DeltagareComponent,
},
{
path: ':deltagareId',
loadChildren: () => import('./pages/deltagare-card/deltagare-card.module').then(m => m.DeltagareCardModule),
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class DeltagareRoutingModule {}

View File

@@ -0,0 +1,17 @@
<dafa-layout>
<digi-typography>
<section class="deltagare">
<h1>Deltagarlista</h1>
<p>
Här ser du en lista på de deltagare du är tilldelad. Klicka på deltagarens namn för att öppna och se mer
information om deltagarna.
</p>
<a routerLink="1">Klicka för att gå till en test-deltagare från API:et</a>
<ul *ngIf="allDeltagare$ | async as allDeltagare">
<li *ngFor="let deltagare of allDeltagare"><a [routerLink]="deltagare.id">{{deltagare.fullName}}</a></li>
</ul>
</section>
</digi-typography>
</dafa-layout>

View File

@@ -0,0 +1,2 @@
.deltagare {
}

View File

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

View File

@@ -0,0 +1,16 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Deltagare } from '@dafa-models/deltagare.model';
import { DeltagareService } from '@dafa-services/api/deltagare.service';
import { Observable } from 'rxjs';
@Component({
selector: 'dafa-deltagare',
templateUrl: './deltagare.component.html',
styleUrls: ['./deltagare.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeltagareComponent {
allDeltagare$: Observable<Deltagare[]> = this.deltagareService.allDeltagare$;
constructor(private deltagareService: DeltagareService) {}
}

View File

@@ -0,0 +1,12 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
import { DeltagareRoutingModule } from './deltagare-routing.module';
import { DeltagareComponent } from './deltagare.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [DeltagareComponent],
imports: [CommonModule, DeltagareRoutingModule, LayoutModule],
})
export class DeltagareModule {}

View File

@@ -0,0 +1,81 @@
<dafa-layout>
<section class="deltagare-card">
<digi-typography *ngIf="deltagare$ | async as deltagare; else loadingRef">
<header class="deltagare-card__header">
<dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link>
<h1>{{ deltagare.fullName }}</h1>
</header>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus accusantium sit, reprehenderit, esse suscipit
quis similique harum est eum eveniet aspernatur delectus magni asperiores porro aliquam voluptate! Architecto,
perferendis commodi.
</p>
<pre>{{deltagare | json}}</pre>
<div class="deltagare-card__contents">
<div class="deltagare-card__column">
<h2>Personuppgifter</h2>
<dl>
<dt>Namn</dt>
<dd *ngIf="deltagare.fullName; else emptyDD">{{ deltagare.fullName }}</dd>
<dt>Personnummer</dt>
<dd *ngIf="deltagare.ssn; else emptyDD">{{ deltagare.ssn }}</dd>
<dt>Epostadress</dt>
<dd *ngIf="deltagare.email; else emptyDD">{{ deltagare.email }}</dd>
<dt>Telefonnummer</dt>
<ng-container *ngIf="deltagare.phoneNumbers.length; else emptyDD">
<ng-container *ngFor="let phoneNumber of deltagare.phoneNumbers">
<dd>{{ phoneNumber.type }}: {{phoneNumber.number}}</dd>
</ng-container>
</ng-container>
</dl>
<h3>Särskilda behov</h3>
<p>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Minus, voluptatum quibusdam repellendus animi,
quidem, commodi quos porro quia incidunt saepe veritatis voluptatem. Cupiditate, accusamus atque! Illum,
quisquam esse? Omnis, quasi!
</p>
</div>
<div class="deltagare-card__column">
<h2>Om tjänsten</h2>
</div>
<div class="deltagare-card__column">
<h2>Matchningsuppgifter</h2>
</div>
<div class="deltagare-card__column">
<h2>Körkortsinformation</h2>
<dl>
<dt>Har körkort</dt>
<dd>{{deltagare.driversLicense.licenses.length ? 'Ja' : 'Nej'}}</dd>
<ng-container *ngIf="deltagare.driversLicense.licenses.length">
<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>
<footer class="deltagare-card__footer">
<dafa-back-link [route]="['/deltagare']">Tillbaka till deltagarlistan</dafa-back-link>
</footer>
</digi-typography>
</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>
</dafa-layout>

View File

@@ -0,0 +1,45 @@
@import 'variables/gutters';
.deltagare-card {
&__contents {
display: flex;
flex-direction: column;
gap: $digi--layout--gutter--xl $digi--layout--gutter--l;
h2 {
margin-top: 0;
}
}
&__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 {
grid-column: 1;
font-weight: var(--digi--typography--font-weight--semibold);
}
dd {
grid-column: 2;
}
&__header,
&__footer {
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
}
}

View File

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

View File

@@ -0,0 +1,25 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { IconType } from '@dafa-enums/icon-type.enum';
import { Deltagare } from '@dafa-models/deltagare.model';
import { DeltagareService } from '@dafa-services/api/deltagare.service';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
@Component({
selector: 'dafa-deltagare-card',
templateUrl: './deltagare-card.component.html',
styleUrls: ['./deltagare-card.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeltagareCardComponent {
private _deltagareId$: Observable<string> = this.activatedRoute.params.pipe(
map(({ deltagareId }) => deltagareId as string)
);
deltagare$: Observable<Deltagare> = this._deltagareId$.pipe(
switchMap(deltagareId => this.deltagaresService.deltagare$(deltagareId))
);
iconType = IconType;
constructor(private activatedRoute: ActivatedRoute, private deltagaresService: DeltagareService) {}
}

View File

@@ -0,0 +1,23 @@
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 { DeltagareCardComponent } from './deltagare-card.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [DeltagareCardComponent],
imports: [
CommonModule,
RouterModule.forChild([{ path: '', component: DeltagareCardComponent }]),
LayoutModule,
DigiNgLinkInternalModule,
IconModule,
BackLinkModule,
],
exports: [DeltagareCardComponent],
})
export class DeltagareCardModule {}

View File

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

View File

@@ -0,0 +1,17 @@
export const DRIVERS_LICENSES = [
'AM',
'A1',
'A2',
'A',
'B',
'BE',
'B96',
'C1',
'C',
'C1E',
'CE',
'D1',
'D',
'D1E',
'DE',
];

View File

@@ -1,4 +1,4 @@
export const Navigation = {
export const NAVIGATION = {
administration: 'Administration',
'skapa-konto': 'Skapa nytt konto',
personal: 'Hantera personal',

View File

@@ -0,0 +1,16 @@
export enum AddressType {
OFFICIAL = 'Folkbokföringsadress',
POSTAL = 'Postadress',
UNSPECIFIED = 'Ospecificerad adress',
}
export function getAddressType(addressType: 'FBF' | 'EgenAngiven'): AddressType {
switch (addressType) {
case 'FBF':
return AddressType.OFFICIAL;
case 'EgenAngiven':
return AddressType.POSTAL;
default:
return AddressType.UNSPECIFIED;
}
}

View File

@@ -0,0 +1,17 @@
export enum PhoneNumberType {
CELL = 'Mobil',
DOMESTIC = 'Hem',
WORK = 'Arbete',
UNKNOWN = 'Okänd',
}
export function getPhoneNumberType(phoneNumberType: 'Mobil' | 'Bostad'): PhoneNumberType {
switch (phoneNumberType) {
case 'Mobil':
return PhoneNumberType.CELL;
case 'Bostad':
return PhoneNumberType.DOMESTIC;
default:
return PhoneNumberType.UNKNOWN;
}
}

View File

@@ -0,0 +1,20 @@
import { AddressType, getAddressType } from '@dafa-enums/address-type.enum';
import { AddressResponse } from './api/address.response.model';
export interface Address {
type: AddressType;
street: string;
postalCode: string;
city: string;
country: string;
}
export function mapResponseToAddress(data: AddressResponse): Address {
return {
type: getAddressType(data.adresstyp),
street: data.gatuadress,
postalCode: data.postnummer,
city: data.postort,
country: data.land,
};
}

View File

@@ -0,0 +1,7 @@
export interface AddressResponse {
adresstyp: 'FBF' | 'EgenAngiven';
gatuadress: string;
postnummer: string;
postort: string;
land: string;
}

View File

@@ -0,0 +1,11 @@
import { AddressResponse } from './address.response.model';
import { PhoneNumberResponse } from './phonenumber.response.model';
export interface ContactInformationResponse {
fornamn: string;
efternamn: string;
personnummer: string;
epost: string;
telekomadresser: PhoneNumberResponse[];
adresser: AddressResponse[];
}

View File

@@ -0,0 +1,18 @@
import { ContactInformationResponse } from './contact-information.response.model';
import { DisabilitiesResponse } from './disabilities.response.model';
import { DriversLicenseResponse } from './drivers-license.response.model';
import { EducationsResponse } from './educations.response.model';
import { HighestEducationResponse } from './highest-education.response.model';
import { TranslatorResponse } from './translator.response.model';
import { WorkLanguagesResponse } from './work-languages.response.model';
export interface DeltagareResponse {
id: string;
contact: ContactInformationResponse;
driverlicense: DriversLicenseResponse;
highestEducation: HighestEducationResponse;
educations: EducationsResponse;
translator: TranslatorResponse;
workLanguages: WorkLanguagesResponse;
disabilities: DisabilitiesResponse;
}

View File

@@ -0,0 +1,5 @@
import { DisabilityResponse } from './disability.response.model';
export interface DisabilitiesResponse {
funktionsnedsattningar: DisabilityResponse[];
}

View File

@@ -0,0 +1,6 @@
export interface DisabilityResponse {
kod: string;
funktionsnedsattning: string;
beskrivning: string;
utgatt: boolean;
}

View File

@@ -0,0 +1,4 @@
export interface DriversLicenseResponse {
korkort: { behorighet: string };
tillgang_till_bil: boolean;
}

View File

@@ -0,0 +1,5 @@
export interface EducationLevelResponse {
utbildningsniva: string;
beskrivning: string;
taxonomy_id: number;
}

View File

@@ -0,0 +1,7 @@
export interface EducationResponse {
utbildning: string;
beskrivning: string;
anordnare: string;
period_from: string;
period_tom: string;
}

View File

@@ -0,0 +1,5 @@
import { EducationResponse } from './education.response.model';
export interface EducationsResponse {
utbildningar: EducationResponse[];
}

View File

@@ -0,0 +1,6 @@
export interface HighestEducationResponse {
utbildningsniva: string;
beskrivning_utbildningsniva: string;
sun_kod: string;
beskrivning_sun_kod: string;
}

View File

@@ -0,0 +1,3 @@
export interface LanguageResponse {
beskrivning: string;
}

View File

@@ -0,0 +1,5 @@
export interface PhoneNumberResponse {
landskod: number;
nummer_utan_inledande_nolla: number;
telekomtyp: 'Mobil' | 'Bostad';
}

View File

@@ -0,0 +1,4 @@
export interface SunKodResponse {
sun_kod: string;
beskrivning: string;
}

View File

@@ -0,0 +1,5 @@
import { LanguageResponse } from './language.response.model';
export interface TranslatorResponse {
sprak: LanguageResponse;
}

View File

@@ -0,0 +1,7 @@
export interface WorkExperienceResponse {
yrke: string;
beskrivning: string;
arbetsgivare: string;
period_from: string;
period_tom: string;
}

View File

@@ -0,0 +1,5 @@
import { WorkExperienceResponse } from './work-experience.response.model';
export interface WorkExperiencesResponse {
arbetslivserfarenheter: WorkExperienceResponse[];
}

View File

@@ -0,0 +1,5 @@
import { LanguageResponse } from './language.response.model';
export interface WorkLanguagesResponse {
sprak: LanguageResponse[];
}

View File

@@ -0,0 +1,34 @@
import { Address, mapResponseToAddress } from './address.model';
import { ContactInformationResponse } from './api/contact-information.response.model';
import { mapResponseToPhoneNumber, PhoneNumber } from './phonenumber.model';
export interface ContactInformation {
firstName: string;
lastName: string;
fullName: string;
ssn: string;
email: string;
phoneNumbers: PhoneNumber[];
addresses: Address[];
}
export function mapResponseToContactInformation(contactInformation: ContactInformationResponse): ContactInformation {
return {
firstName: contactInformation.fornamn,
lastName: contactInformation.efternamn,
fullName: `${contactInformation.fornamn} ${contactInformation.efternamn}`,
ssn: `${contactInformation.personnummer.substring(
0,
contactInformation.personnummer.length - 4
)}-${contactInformation.personnummer.substring(contactInformation.personnummer.length - 4)}`,
email: contactInformation.epost,
phoneNumbers: contactInformation.telekomadresser
? contactInformation.telekomadresser.map(phoneNumber => {
return mapResponseToPhoneNumber(phoneNumber);
})
: [],
addresses: contactInformation.adresser
? contactInformation.adresser.map(address => mapResponseToAddress(address))
: null,
};
}

View File

@@ -0,0 +1,45 @@
import { Address } from './address.model';
import { DeltagareResponse } from './api/deltagare.response.model';
import { mapResponseToContactInformation } from './contact-information.model';
import { Disability, mapResponseToDisability } from './disability.model';
import { DriversLicense, mapResponseToDriversLicense } from './drivers-license.model';
import { Education, mapResponseToEducation } from './education.model';
import { HighestEducation, mapResponseToHighestEducation } from './highest-education.model';
import { PhoneNumber } from './phonenumber.model';
export interface DeltagareCompact {
id: string;
fullName: string;
}
export interface Deltagare extends DeltagareCompact {
firstName: string;
lastName: string;
ssn: string;
email: string;
phoneNumbers: PhoneNumber[];
addresses: Address[];
driversLicense: DriversLicense;
educations: Education[];
highestEducation: HighestEducation;
translator: string;
disabilities: Disability[];
workLanguages: string[];
// workExperiences: WorkExperience[]; // TODO: Missing from API
}
export function mapResponseToDeltagare(data: DeltagareResponse): Deltagare {
const { id, contact, driverlicense, highestEducation, educations, translator, workLanguages, disabilities } = data;
return {
id,
...mapResponseToContactInformation(contact),
driversLicense: mapResponseToDriversLicense(driverlicense),
highestEducation: highestEducation && mapResponseToHighestEducation(highestEducation),
educations: educations && educations.utbildningar.map(education => mapResponseToEducation(education)),
translator: translator && translator.sprak.beskrivning,
workLanguages: workLanguages && workLanguages.sprak.map(language => language.beskrivning),
disabilities:
disabilities && disabilities.funktionsnedsattningar.map(disability => mapResponseToDisability(disability)),
};
}

View File

@@ -0,0 +1,17 @@
import { DisabilityResponse } from './api/disability.response.model';
export interface Disability {
code: string;
title: string;
description: string;
}
export function mapResponseToDisability(data: DisabilityResponse): Disability {
const { kod, funktionsnedsattning, beskrivning } = data;
return {
code: kod,
title: funktionsnedsattning, // TODO: Needed from API
description: beskrivning || null, //TODO: Needed from API
};
}

View File

@@ -0,0 +1,29 @@
import { DRIVERS_LICENSES } from '@dafa-constants/drivers-licenses';
import { DriversLicenseResponse } from './api/drivers-license.response.model';
export interface DriversLicense {
licenses: string[];
accessToCar: boolean;
}
function mapLicensesAsStringToArray(licenses = ''): string[] {
const allLicenses = DRIVERS_LICENSES.sort((a, b) => b.length - a.length);
let search = licenses;
const found: string[] = [];
allLicenses.forEach(license => {
if (search.indexOf(license) >= 0) {
found.push(license);
search = search.replace(license, '');
}
});
return found;
}
export function mapResponseToDriversLicense(data: DriversLicenseResponse): DriversLicense {
return {
licenses: mapLicensesAsStringToArray(data.korkort.behorighet),
accessToCar: data.tillgang_till_bil,
};
}

View File

@@ -0,0 +1,21 @@
import { EducationResponse } from './api/education.response.model';
export interface Education {
education: string;
description: string;
organizer: string;
dateFrom: string;
dateTo: string;
}
export function mapResponseToEducation(data: EducationResponse): Education {
const { utbildning, beskrivning, anordnare, period_from, period_tom } = data;
return {
education: utbildning,
description: beskrivning,
organizer: anordnare,
dateFrom: period_from,
dateTo: period_tom,
};
}

View File

@@ -0,0 +1,27 @@
import { HighestEducationResponse } from './api/highest-education.response.model';
export interface HighestEducation {
level: {
code: string;
description: string;
};
sunKod: {
code: string;
description: string;
};
}
export function mapResponseToHighestEducation(data: HighestEducationResponse): HighestEducation {
const { utbildningsniva, beskrivning_utbildningsniva, sun_kod, beskrivning_sun_kod } = data;
return {
level: {
code: utbildningsniva,
description: beskrivning_utbildningsniva,
},
sunKod: {
code: sun_kod,
description: beskrivning_sun_kod,
},
};
}

View File

@@ -0,0 +1,14 @@
import { getPhoneNumberType, PhoneNumberType } from '@dafa-enums/phonenumber-type.enum';
import { PhoneNumberResponse } from './api/phonenumber.response.model';
export interface PhoneNumber {
type: PhoneNumberType;
number: string;
}
export function mapResponseToPhoneNumber(data: PhoneNumberResponse): PhoneNumber {
return {
type: getPhoneNumberType(data.telekomtyp),
number: `+${data.landskod}${data.nummer_utan_inledande_nolla}`,
};
}

View File

@@ -0,0 +1,21 @@
import { WorkExperienceResponse } from './api/work-experience.response.model';
export interface WorkExperience {
profession: string;
description: string;
employer: string;
dateFrom: string;
dateTo: string;
}
export function mapResponseToWorkExperience(data: WorkExperienceResponse): WorkExperience {
const { yrke, beskrivning, arbetsgivare, period_from, period_tom } = data;
return {
profession: yrke,
description: beskrivning,
employer: arbetsgivare,
dateFrom: period_from,
dateTo: period_tom,
};
}

View File

@@ -0,0 +1,152 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@dafa-environment';
import { ContactInformationResponse } from '@dafa-models/api/contact-information.response.model';
import { DeltagareResponse } from '@dafa-models/api/deltagare.response.model';
import { DisabilitiesResponse } from '@dafa-models/api/disabilities.response.model';
import { DriversLicenseResponse } from '@dafa-models/api/drivers-license.response.model';
import { EducationsResponse } from '@dafa-models/api/educations.response.model';
import { HighestEducationResponse } from '@dafa-models/api/highest-education.response.model';
import { TranslatorResponse } from '@dafa-models/api/translator.response.model';
import { WorkExperiencesResponse } from '@dafa-models/api/work-experiences.response.model';
import { WorkLanguagesResponse } from '@dafa-models/api/work-languages.response.model';
import { ContactInformation, mapResponseToContactInformation } from '@dafa-models/contact-information.model';
import { Deltagare, DeltagareCompact, mapResponseToDeltagare } from '@dafa-models/deltagare.model';
import { Disability, mapResponseToDisability } from '@dafa-models/disability.model';
import { DriversLicense, mapResponseToDriversLicense } from '@dafa-models/drivers-license.model';
import { Education, mapResponseToEducation } from '@dafa-models/education.model';
import { HighestEducation, mapResponseToHighestEducation } from '@dafa-models/highest-education.model';
import { mapResponseToWorkExperience, WorkExperience } from '@dafa-models/work-experience.model';
import { combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
const API_HEADERS = { headers: environment.api.headers };
@Injectable({
providedIn: 'root',
})
export class DeltagareService {
private _apiBaseUrl = `${environment.api.url}/customerinfo`;
private _fetchAllDeltagare: Observable<DeltagareResponse[]> = this.httpClient
.get<{ data: DeltagareResponse[] }>(`${this._apiBaseUrl}`, { ...API_HEADERS })
.pipe(
map(response => {
return response.data;
})
);
public allDeltagare$: Observable<Deltagare[]> = this._fetchAllDeltagare.pipe(
map(data => {
return data.map(deltagare => mapResponseToDeltagare(deltagare));
})
);
private _fetchContactInformation$(id: string): Observable<ContactInformation> {
return this.httpClient
.get<{ data: ContactInformationResponse }>(`${this._apiBaseUrl}/contact/${id}`, { ...API_HEADERS })
.pipe(map(response => mapResponseToContactInformation(response.data)));
}
private _fetchDriversLicense$(id: string): Observable<DriversLicense> {
return this.httpClient
.get<{ data: DriversLicenseResponse }>(`${this._apiBaseUrl}/driverlicense/${id}`, { ...API_HEADERS })
.pipe(map(response => mapResponseToDriversLicense(response.data)));
}
private _fetchHighestEducation$(id: string): Observable<HighestEducation> {
return this.httpClient
.get<{ data: HighestEducationResponse }>(`${this._apiBaseUrl}/education/highest/${id}`, { ...API_HEADERS })
.pipe(map(response => mapResponseToHighestEducation(response.data)));
}
private _fetchEducations$(id: string): Observable<Education[]> {
return this.httpClient
.get<{ data: EducationsResponse }>(`${this._apiBaseUrl}/education/${id}`, { ...API_HEADERS })
.pipe(
map(response =>
response.data.utbildningar
? response.data.utbildningar.map(utbildning => mapResponseToEducation(utbildning))
: []
)
);
}
private _fetchTranslator$(id: string): Observable<string> {
return this.httpClient
.get<{ data: TranslatorResponse }>(`${this._apiBaseUrl}/translator/${id}`, { ...API_HEADERS })
.pipe(map(response => (response.data.sprak ? response.data.sprak.beskrivning : null)));
}
private _fetchWorkLanguages$(id: string): Observable<string[]> {
return this.httpClient
.get<{ data: WorkLanguagesResponse }>(`${this._apiBaseUrl}/work/languages/${id}`, { ...API_HEADERS })
.pipe(map(response => (response.data.sprak ? response.data.sprak.map(sprak => sprak.beskrivning) : [])));
}
private _fetchDisabilities$(id: string): Observable<Disability[]> {
return this.httpClient
.get<{ data: DisabilitiesResponse }>(`${this._apiBaseUrl}/work/disability/${id}`, { ...API_HEADERS })
.pipe(
map(response =>
response.data.funktionsnedsattningar
? response.data.funktionsnedsattningar.map(funktionsnedsattning =>
mapResponseToDisability(funktionsnedsattning)
)
: []
)
);
}
private _fetchWorkExperiences$(id: string): Observable<WorkExperience[]> {
return this.httpClient
.get<{ data: WorkExperiencesResponse }>(`${this._apiBaseUrl}/work/${id}`, { ...API_HEADERS })
.pipe(
map(response =>
response.data.arbetslivserfarenheter
? response.data.arbetslivserfarenheter.map(erfarenhet => mapResponseToWorkExperience(erfarenhet))
: []
)
);
}
public deltagareCompact$(id: string): Observable<DeltagareCompact> {
return this._fetchContactInformation$(id).pipe(
map(contactInformation => ({
id,
fullName: contactInformation.fullName,
}))
);
}
// As TypeScript has some limitations regarding combining Observables this way,
// we need to type it manually when exceeding 6 Observables inside a combineLatest.
// Read: https://github.com/ReactiveX/rxjs/issues/3601#issuecomment-384711601
public deltagare$(id: string): Observable<Deltagare> {
return combineLatest([
this._fetchContactInformation$(id),
this._fetchDriversLicense$(id),
this._fetchHighestEducation$(id),
this._fetchEducations$(id),
this._fetchTranslator$(id),
this._fetchWorkLanguages$(id),
this._fetchDisabilities$(id),
]).pipe(
map(
([contactInformation, driversLicense, highestEducation, educations, translator, workLanguages, disabilities]: [
ContactInformation,
DriversLicense,
HighestEducation,
Education[],
string,
string[],
Disability[]
]) => ({
id,
...contactInformation,
driversLicense,
highestEducation,
educations,
translator,
workLanguages,
disabilities,
})
)
);
}
constructor(private httpClient: HttpClient) {}
}

View File

@@ -1,5 +1,5 @@
import { Navigation } from '@dafa-constants/navigation';
import { NAVIGATION } from '@dafa-constants/navigation';
export function mapPathToPageName(path: string): string {
return (Navigation[path] || `${path.charAt(0).toUpperCase()}${path.slice(1)}`) as string;
return (NAVIGATION[path] || `${path.charAt(0).toUpperCase()}${path.slice(1)}`) as string;
}