Pull request #291: Feature/TV-945 felhantering 2

Merge in TEA/mina-sidor-fa-web from feature/TV-945-felhantering-2 to develop

Squashed commit of the following:

commit 9e581d36dfecb901fbd4c04eb5b8a80e77a51216
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 15:29:20 2021 +0100

    Fixed last few error-handling issues

commit eb35f23d05d8584673ea3f8f28a67206bb21a3cf
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 15:17:45 2021 +0100

    Renamed api-services

commit e2764cb623701afadfb6455e77b8f6e718c1523a
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 15:13:54 2021 +0100

    Improved error-handling for user and refactored user(api)service

commit 78cbdc6695653646eee73f1583ef6e272158d50a
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:53:52 2021 +0100

    Improved error-handling for tjanst

commit 9b4ae985f9a92ed1eb7a9d823b37ce7cc069c417
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:35:41 2021 +0100

    Improved error-handling for slutredovisning

commit 37bb43bde8151075450cd988715d6b9cb2ab8b1b
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:32:18 2021 +0100

    Improved error-handling for signal

commit a8e3bfb4a222d05abfdcb5b415dc93682731c14d
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:23:22 2021 +0100

    Improved error-handling for periodisk redovisning

commit f1eb5cb768fb662412ef73026586a88982ea56c7
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:19:24 2021 +0100

    Improved error-handling for news

commit cd81cade46bc28d70a67f3a54dc571c3e348606a
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:19:15 2021 +0100

    Improved error-handling for informativ rapport

commit bff13ae4e54b40546266d46f0595aa3594cf32ca
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:16:29 2021 +0100

    Improved error-handling for handlingar

commit 9264f0aa63fdb6e260cf3221cee838795bd095dc
Merge: 174264e4 8f0b7016
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Tue Dec 7 13:05:30 2021 +0100

    Merge branch 'develop' into feature/TV-945-felhantering-2

commit 174264e495296c87f6d60b5e017a95b8f0efe76e
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Dec 6 12:59:41 2021 +0100

    Improved error-handling for handledare

commit c1430f375f3baf604ec153405f40eb51c84b5eb9
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date:   Mon Dec 6 12:48:18 2021 +0100

    Improved error-handling for export, frånvaroreport, gemensam planering
This commit is contained in:
Erik Tiekstra
2021-12-10 08:07:06 +01:00
parent 9ecd0c11d7
commit 9d96f0d972
44 changed files with 483 additions and 381 deletions

View File

@@ -1,6 +1,6 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Role } from '@msfa-models/role.model';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';

View File

@@ -7,11 +7,11 @@ import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import { UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import { EmployeeService } from '@msfa-services/api/employee.service';
import { TjanstService } from '@msfa-services/api/tjanst.service';
import { RoleService } from '@msfa-services/role.service';
import { UtforandeVerksamheterService } from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { catchError, mapTo, startWith, switchMap } from 'rxjs/operators';
import { EmployeeFormService } from './services/employee-form.service';
@Component({
selector: 'msfa-employee-form',
@@ -30,7 +30,7 @@ export class EmployeeFormComponent implements OnInit {
errorWhileUpdating$: Observable<CustomError> = this._errorWhileUpdating$.asObservable();
employee$ = this.employeeService.employee$;
tjanster$: Observable<Tjanst[]> = this.tjanstService.tjanster$;
tjanster$: Observable<Tjanst[]> = this.employeeFormService.fetchTjanster$();
availableRoles: Role[] = this.roleService.allRoles;
isLoadingUtforandeVerksamheter$: Observable<boolean>;
@@ -38,7 +38,7 @@ export class EmployeeFormComponent implements OnInit {
constructor(
private employeeService: EmployeeService,
private roleService: RoleService,
private tjanstService: TjanstService,
private employeeFormService: EmployeeFormService,
private utforandeVerksamheterService: UtforandeVerksamheterService,
private activatedRoute: ActivatedRoute,
private router: Router

View File

@@ -2,12 +2,23 @@ import { Injectable } from '@angular/core';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
import { RoleEnum } from '@msfa-enums/role.enum';
import { Role } from '@msfa-models/role.model';
import { Tjanst } from '@msfa-models/tjanst.model';
import { mapResponseToTjanst, Tjanst } from '@msfa-models/tjanst.model';
import { TjanstApiService } from '@msfa-services/api/tjanst.api.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class EmployeeFormService {
constructor(private tjanstApiService: TjanstApiService) {}
fetchTjanster$(): Observable<Tjanst[]> {
return this.tjanstApiService
.fetchTjanster$()
.pipe(map(({ data }) => data.map(tjanst => mapResponseToTjanst(tjanst))));
}
isSelectedRole(role: Role, selectedRoles: RoleEnum[]): boolean {
if (!selectedRoles || !role) {
return false;

View File

@@ -99,9 +99,9 @@ export class EmployeeInviteComponent {
this._lastInvites$.next(data);
this.formGroup.reset();
},
error: error => {
error: (error: CustomError) => {
this.submitIsLoading$.next(false);
throw new CustomError(error);
throw error;
},
complete: () => {
post.unsubscribe();

View File

@@ -14,12 +14,12 @@
(afOnToggle)="setActiveTab('0')"
af-aria-label="Deltagare & tjänst"
af-id="deltagare-card-personal-information"
*ngIf="deltagareTjanstVisible"
*ngIf="deltagareTjanstVisible$ | async"
>
<msfa-deltagare-tab-personal-information
*ngIf="activeTab === '0'"
class="deltagare-card__tab-contents"
[handledarePickerVisible]="handledarePickerVisible"
[handledarePickerVisible]="handledarePickerVisible$ | async"
></msfa-deltagare-tab-personal-information>
</digi-navigation-tab>
@@ -27,7 +27,7 @@
(afOnToggle)="setActiveTab('1')"
af-aria-label="Rapportering"
af-id="deltagare-card-reports"
*ngIf="reportingTabVisible"
*ngIf="reportingTabVisible$ | async"
>
<msfa-deltagare-tab-reports
*ngIf="activeTab === '1'"
@@ -39,7 +39,7 @@
(afOnToggle)="setActiveTab('2')"
af-aria-label="Erfarenheter"
af-id="deltagare-card-experiences"
*ngIf="experiencesVisible"
*ngIf="experiencesVisible$ | async"
>
<msfa-deltagare-tab-experiences
*ngIf="activeTab === '2'"
@@ -51,7 +51,7 @@
(afOnToggle)="setActiveTab('3')"
af-aria-label="Känsliga uppgifter"
af-id="deltagare-card-sensitive-information"
*ngIf="sensitiveDataVisible"
*ngIf="sensitiveDataVisible$ | async"
>
<msfa-deltagare-tab-sensitive-information
*ngIf="activeTab === '3'"

View File

@@ -6,7 +6,7 @@ import { RoleEnum } from '@msfa-enums/role.enum';
import { environment } from '@msfa-environment';
import { ContactInformation } from '@msfa-models/contact-information.model';
import { Role } from '@msfa-models/role.model';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { DeltagareCardService } from './deltagare-card.service';
@@ -24,7 +24,33 @@ export class DeltagareCardComponent extends UnsubscribeDirective implements OnDe
);
private _activeFeatures: Feature[] = environment.activeFeatures;
private _userRoles: Role[] = this.userService.userRolesSnapshot;
private _userRoles$: Observable<Role[]> = this.userService.userRoles$;
deltagareTjanstVisible$: Observable<boolean> = this._userRoles$.pipe(
map(roles =>
roles.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning || role.type === RoleEnum.MSFA_ReceiveDeltagare)
)
);
handledarePickerVisible$: Observable<boolean> = this._userRoles$.pipe(
map(roles => roles.some(role => role.type === RoleEnum.MSFA_ReceiveDeltagare))
);
reportingTabVisible$: Observable<boolean> = this._userRoles$.pipe(
map(
roles =>
roles.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning) &&
this._activeFeatures.includes(Feature.REPORTING)
)
);
experiencesVisible$: Observable<boolean> = this._userRoles$.pipe(
map(roles => roles.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning))
);
sensitiveDataVisible$: Observable<boolean> = this._userRoles$.pipe(
map(
roles =>
roles.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning) &&
this._activeFeatures.includes(Feature.DELTAGARE_SENSITIVE_INFORMATION)
)
);
contactInformation$: Observable<ContactInformation> = this.deltagareCardService.contactInformation$;
@@ -41,34 +67,6 @@ export class DeltagareCardComponent extends UnsubscribeDirective implements OnDe
);
}
get deltagareTjanstVisible(): boolean {
return this._userRoles?.some(
role => role.type === RoleEnum.MSFA_ReportAndPlanning || role.type === RoleEnum.MSFA_ReceiveDeltagare
);
}
get handledarePickerVisible(): boolean {
return this._userRoles?.some(role => role.type === RoleEnum.MSFA_ReceiveDeltagare);
}
get reportingTabVisible(): boolean {
return (
this._activeFeatures.includes(Feature.REPORTING) &&
this._userRoles?.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning)
);
}
get experiencesVisible(): boolean {
return this._userRoles?.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning);
}
get sensitiveDataVisible(): boolean {
return (
this._activeFeatures.includes(Feature.DELTAGARE_SENSITIVE_INFORMATION) &&
this._userRoles?.some(role => role.type === RoleEnum.MSFA_ReportAndPlanning)
);
}
setActiveTab(tabId: string): void {
this.deltagareCardService.setActiveTab(tabId);
}

View File

@@ -3,7 +3,7 @@ import { AvvikelseReportRequest } from '@msfa-models/api/avvikelse-request.model
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { AvvikelseQuestion } from '@msfa-models/avvikelse-question.model';
import { AvvikelseReason, sortAvvikelseReasons } from '@msfa-models/avvikelse-reason.model';
import { AvvikelseApiService } from '@msfa-services/api/avvikelse-api.service';
import { AvvikelseApiService } from '@msfa-services/api/avvikelse.api.service';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';

View File

@@ -2,17 +2,21 @@ import { Injectable } from '@angular/core';
import { Activity } from '@msfa-models/activity.model';
import { GemensamPlaneringPostRequest } from '@msfa-models/api/gemensam-planering.request.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering.api.service';
import { Observable } from 'rxjs';
@Injectable()
export class GemensamPlaneringFormService {
public activities$: Observable<Activity[]> = this.gemensamPlaneringApiService.fetchActivities$();
constructor(private gemensamPlaneringApiService: GemensamPlaneringApiService) {}
constructor(
private gemensamPlaneringApiService: GemensamPlaneringApiService,
private deltagareApiService: DeltagareApiService
) {}
public fetchAvropInformation$(genomforandeReferens: number): Observable<DeltagareAvrop> {
return this.gemensamPlaneringApiService.fetchAvropInformation$(genomforandeReferens);
return this.deltagareApiService.fetchAvropInformation$(genomforandeReferens);
}
public postGemensamPlanering$(requestData: GemensamPlaneringPostRequest): Observable<void> {

View File

@@ -3,7 +3,7 @@ import { Activity, mapResponseToActivity } from '@msfa-models/activity.model';
import { PeriodiskRedovisningRequest } from '@msfa-models/api/periodisk-redovisning.request.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering.api.service';
import { PeriodiskRedovisningApiService } from '@msfa-services/api/periodisk-redovisning.api.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@@ -26,7 +26,7 @@ export class PeriodiskRedovisningFormService {
getAllChosenActivities(genomforandeReferens: number): Observable<Activity[]> {
return this.gemensamPlaneringApiService
.fetchAllChosenActivities(genomforandeReferens)
.fetchAllChosenActivities$(genomforandeReferens)
.pipe(map(({ data }) => data.map(activity => mapResponseToActivity(activity))));
}
}

View File

@@ -4,7 +4,7 @@ import { SlutredovisningRequest } from '@msfa-models/api/slutredovisning.request
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { mapResponseToYrkesomrade, Yrkesomrade, yrkeToTextMap } from '@msfa-models/yrkesomrade.model';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering.api.service';
import { SlutredovisningApiService } from '@msfa-services/api/slutredovisning.api.service';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, shareReplay } from 'rxjs/operators';
@@ -70,7 +70,7 @@ export class SlutredovisningFormService {
getAllChosenActivities(genomforandeReferens: number): Observable<Activity[]> {
return this.gemensamPlaneringApiService
.fetchAllChosenActivities(genomforandeReferens)
.fetchAllChosenActivities$(genomforandeReferens)
.pipe(map(({ data }) => data.map(activity => mapResponseToActivity(activity))));
}
}

View File

@@ -3,7 +3,7 @@ import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { AvvikelseQuestion } from '@msfa-models/avvikelse-question.model';
import { AvvikelseReason } from '@msfa-models/avvikelse-reason.model';
import { AvvikelseReport, mapResponseToAvvikelse } from '@msfa-models/avvikelse.model';
import { AvvikelseApiService } from '@msfa-services/api/avvikelse-api.service';
import { AvvikelseApiService } from '@msfa-services/api/avvikelse.api.service';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { HandlingarApiService } from '@msfa-services/api/handlingar.api.service';
import { combineLatest, Observable } from 'rxjs';

View File

@@ -6,7 +6,7 @@ import {
mapResponseToGemensamPlaneringDetailed,
} from '@msfa-models/gemensam-planering.model';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering.api.service';
import { HandlingarApiService } from '@msfa-services/api/handlingar.api.service';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';

View File

@@ -3,8 +3,8 @@ import { Activity } from '@msfa-models/activity.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { mapResponseToPeriodiskRedovisning, PeriodiskRedovisning } from '@msfa-models/periodisk-redovisning.model';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering-api.service';
import { PeriodiskRedovisningApiService } from '@msfa-services/api/periodisk-redovisning.api.service';
import { GemensamPlaneringApiService } from '@msfa-services/api/gemensam-planering.api.service';
import { HandlingarApiService } from '@msfa-services/api/handlingar.api.service';
import { Observable } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
@@ -13,7 +13,7 @@ export class PeriodiskRedovisningViewService {
private _activities$: Observable<Activity[]> = this.gemensamPlaneringApiService.fetchActivities$();
constructor(
private periodiskRedovisningApiService: PeriodiskRedovisningApiService,
private handlingarApiService: HandlingarApiService,
private gemensamPlaneringApiService: GemensamPlaneringApiService,
private deltagareApiService: DeltagareApiService
) {}
@@ -25,7 +25,7 @@ export class PeriodiskRedovisningViewService {
public fetchPeriodiskRedovisning$(handlingId: string): Observable<PeriodiskRedovisning> {
return this._activities$.pipe(
switchMap(activities =>
this.periodiskRedovisningApiService
this.handlingarApiService
.fetchPeriodiskRedovisning$(handlingId)
.pipe(map(({ data }) => mapResponseToPeriodiskRedovisning(data, activities)))
)

View File

@@ -4,8 +4,8 @@ import { environment } from '@msfa-environment';
import { Employee } from '@msfa-models/employee.model';
import { Organization } from '@msfa-models/organization.model';
import { Role } from '@msfa-models/role.model';
import { UserService } from '@msfa-services/api/user.service';
import { RoleService } from '@msfa-services/role.service';
import { UserService } from '@msfa-services/user.service';
import { UiIconType } from '@ui/icon/icon-type.enum';
import { combineLatest, Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';

View File

@@ -3,7 +3,7 @@ import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
import { Organization } from '@msfa-models/organization.model';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { Observable } from 'rxjs';
import { filter } from 'rxjs/operators';

View File

@@ -3,7 +3,7 @@ import { Feature } from '@msfa-enums/feature.enum';
import { environment } from '@msfa-environment';
import { News } from '@msfa-models/news.model';
import { Role } from '@msfa-models/role.model';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { StartService } from './start.service';

View File

@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { CustomError } from '@msfa-models/error/custom-error';
import { mapNewsResponseToNews, News } from '@msfa-models/news.model';
import { NewsApiService } from '@msfa-services/api/news.api.service';
import { BehaviorSubject, Observable } from 'rxjs';
@@ -19,7 +20,7 @@ export class StartService {
this._newsLoading$.next(false);
return mapNewsResponseToNews(response);
}),
catchError(error => {
catchError((error: CustomError) => {
this._newsLoading$.next(false);
throw error;
})

View File

@@ -14,4 +14,4 @@
<msfa-footer class="msfa__footer"></msfa-footer>
</div>
<ui-loader *ngIf="(userLoading$ | async) || (rolesLoading$ | async)" uiType="full-screen"></ui-loader>
<ui-loader *ngIf="userLoading$ | async" uiType="full-screen"></ui-loader>

View File

@@ -6,10 +6,10 @@ import { Employee } from '@msfa-models/employee.model';
import { Organization } from '@msfa-models/organization.model';
import { Role } from '@msfa-models/role.model';
import { AuthenticationService } from '@msfa-services/api/authentication.service';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { mapPathsToBreadcrumbs } from '@msfa-utils/map-paths-to-breadcrumbs.util';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
import { filter, switchMap } from 'rxjs/operators';
@Component({
selector: 'msfa-layout',
@@ -22,8 +22,11 @@ export class LayoutComponent extends UnsubscribeDirective {
selectedOrganization$: Observable<Organization> = this.userService.selectedOrganization$;
user$: Observable<Employee> = this.userService.user$.pipe(filter(user => !!user));
roles$: Observable<Role[]> = this.userService.userRoles$.pipe(filter(roles => !!roles));
userLoading$: Observable<boolean> = this.userService.userLoading$;
rolesLoading$: Observable<boolean> = this.userService.userRolesLoading$;
isLoggedIn$: Observable<boolean> = this.authenticationService.isLoggedIn$;
userLoading$: Observable<boolean> = this.isLoggedIn$.pipe(
filter(isLoggedIn => !!isLoggedIn),
switchMap(() => this.userService.userLoading$)
);
private readonly _startBreadcrumb: NavigationBreadcrumbsItem = {
text: 'Start',
routerLink: '/',

View File

@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { RoleEnum } from '@msfa-enums/role.enum';
import { UserService } from '@msfa-services/api/user.service';
import { UserService } from '@msfa-services/user.service';
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';

View File

@@ -1,7 +1,6 @@
import { HttpClient, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { DeltagareExportRequest } from '@msfa-models/api/deltagare-export.request.model';
import { CustomError } from '@msfa-models/error/custom-error';
@@ -22,9 +21,10 @@ export class ExportApiService {
...requestData,
includeExportedDeltagare: requestData.includeExportedDeltagare.toString(),
};
const apiUrl = `${this._apiBaseUrl}/deltagare`;
return this.httpClient
.get(`${this._apiBaseUrl}/deltagare`, {
.get(apiUrl, {
params,
observe: 'response',
responseType: 'blob' as 'json',
@@ -37,7 +37,9 @@ export class ExportApiService {
throw new CustomError({
error,
message: `Kunde inte hämta exportfilen för deltagare.\n\n${error.message}`,
type: ErrorType.API,
name: `GET ${apiUrl}`,
data: params,
method: 'ExportApiService.fetchDeltagareExportFile$',
});
})
);

View File

@@ -1,13 +1,10 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { FranvaroReasonResponse } from '@msfa-models/api/franvaro-reason.response.model';
import { FranvaroReportRequest } from '@msfa-models/api/franvaro-request.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error';
import { CustomError } from '@msfa-models/error/custom-error';
import { FranvaroReason, mapResponseToFranvaroReason } from '@msfa-models/franvaro-reason.model';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { Observable } from 'rxjs';
import { catchError, filter, map, shareReplay } from 'rxjs/operators';
@@ -17,44 +14,51 @@ import { catchError, filter, map, shareReplay } from 'rxjs/operators';
export class FranvaroReportApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter`;
constructor(private httpClient: HttpClient, private deltagareApiService: DeltagareApiService) {}
constructor(private httpClient: HttpClient) {}
public fetchReasons$(): Observable<FranvaroReason[]> {
return this.httpClient.get<{ data: FranvaroReasonResponse[] }>(`${this._apiBaseUrl}/orsakskoderfranvaro`).pipe(
const apiUrl = `${this._apiBaseUrl}/orsakskoderfranvaro`;
return this.httpClient.get<{ data: FranvaroReasonResponse[] }>(apiUrl).pipe(
filter(response => !!response?.data),
map(({ data }) => data.map(reason => mapResponseToFranvaroReason(reason))),
catchError((error: Error & { status: number }) => {
throw new CustomError(
errorToCustomError({ ...error, message: `Kunde inte hämta orsaker till frånvaro.\n\n${error.message}` })
);
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta orsaker till frånvaro.\n\n${error.message}`,
name: `GET ${apiUrl}`,
method: 'FranvaroReportApiService.fetchReasons$',
});
}),
shareReplay(1)
);
}
public fetchOtherKnownReasons$(): Observable<FranvaroReason[]> {
return this.httpClient.get<{ data: FranvaroReasonResponse[] }>(`${this._apiBaseUrl}/kandaavvikelsekoder`).pipe(
const apiUrl = `${this._apiBaseUrl}/kandaavvikelsekoder`;
return this.httpClient.get<{ data: FranvaroReasonResponse[] }>(apiUrl).pipe(
filter(response => !!response?.data),
map(({ data }) => data.map(reason => mapResponseToFranvaroReason(reason))),
catchError((error: Error & { status: number }) => {
throw new CustomError(
errorToCustomError({ ...error, message: `Kunde inte hämta kända orsaker till frånvaro.\n\n${error.message}` })
);
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta kända orsaker till frånvaro.\n\n${error.message}`,
name: `GET ${apiUrl}`,
method: 'FranvaroReportApiService.fetchOtherKnownReasons$',
});
}),
shareReplay(1)
);
}
public fetchAvropInformation$(genomforandeReferens: number): Observable<DeltagareAvrop> {
return this.deltagareApiService.fetchAvropInformation$(genomforandeReferens);
}
public postFranvaroReport$(requestData: FranvaroReportRequest): Observable<void> {
return this.httpClient.post<void>(`${this._apiBaseUrl}/franvaro`, requestData).pipe(
public postFranvaroReport$(data: FranvaroReportRequest): Observable<void> {
const apiUrl = `${this._apiBaseUrl}/franvaro`;
return this.httpClient.post<void>(apiUrl, data).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Avvikelserapport (frånvaro).\n\n${error.message}`,
type: ErrorType.API,
name: `POST ${apiUrl}`,
data,
method: 'FranvaroReportApiService.postFranvaroReport$',
});
})
);

View File

@@ -1,57 +0,0 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { Activity, mapResponseToActivity } from '@msfa-models/activity.model';
import { ActivityResponse } from '@msfa-models/api/activity.response.model';
import { GemensamPlaneringPostRequest } from '@msfa-models/api/gemensam-planering.request.model';
import { DeltagareAvrop } from '@msfa-models/avrop.model';
import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error';
import { DeltagareApiService } from '@msfa-services/api/deltagare.api.service';
import { Observable } from 'rxjs';
import { catchError, filter, map, shareReplay } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class GemensamPlaneringApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter/gemensam-planering`;
private _apiHandlingarUrl = `${environment.api.url}/handlingar`;
public fetchActivities$(): Observable<Activity[]> {
return this.httpClient.get<{ data: ActivityResponse[] }>(`${this._apiBaseUrl}/aktiviteter`).pipe(
filter(response => !!response?.data),
map(({ data }) => data.map(activity => mapResponseToActivity(activity))),
catchError((error: Error & { status: number }) => {
throw new CustomError(
errorToCustomError({ ...error, message: `Kunde inte hämta aktiviteter.\n\n${error.message}` })
);
}),
shareReplay(1)
);
}
public fetchAvropInformation$(genomforandeReferens: number): Observable<DeltagareAvrop> {
return this.deltagareApiService.fetchAvropInformation$(genomforandeReferens);
}
public fetchAllChosenActivities(genomforandereferens: number): Observable<{ data: ActivityResponse[] }> {
return this.httpClient.get<{ data: ActivityResponse[] }>(
`${this._apiBaseUrl}/alla-valda-aktiviteter/${genomforandereferens}`
);
}
public postGemensamPlanering$(requestData: GemensamPlaneringPostRequest): Observable<void> {
return this.httpClient.post<void>(`${this._apiBaseUrl}`, requestData).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Gemensam planering.\n\n${error.message}`,
type: ErrorType.API,
});
})
);
}
constructor(private httpClient: HttpClient, private deltagareApiService: DeltagareApiService) {}
}

View File

@@ -0,0 +1,65 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@msfa-environment';
import { Activity, mapResponseToActivity } from '@msfa-models/activity.model';
import { ActivityResponse } from '@msfa-models/api/activity.response.model';
import { GemensamPlaneringPostRequest } from '@msfa-models/api/gemensam-planering.request.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Observable } from 'rxjs';
import { catchError, filter, map, shareReplay } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class GemensamPlaneringApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter/gemensam-planering`;
public fetchActivities$(): Observable<Activity[]> {
const apiUrl = `${this._apiBaseUrl}/aktiviteter`;
return this.httpClient.get<{ data: ActivityResponse[] }>(apiUrl).pipe(
filter(response => !!response?.data),
map(({ data }) => data.map(activity => mapResponseToActivity(activity))),
catchError((error: Error & { status: number }) => {
throw new CustomError({
error,
message: `Kunde inte hämta aktiviteter.\n\n${error.message}`,
name: `GET ${apiUrl}`,
method: 'GemensamPlaneringApiService.fetchActivities$',
});
}),
shareReplay(1)
);
}
public fetchAllChosenActivities$(genomforandereferens: number): Observable<{ data: ActivityResponse[] }> {
return this.httpClient
.get<{ data: ActivityResponse[] }>(`${this._apiBaseUrl}/alla-valda-aktiviteter/${genomforandereferens}`)
.pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta valda aktiviteter.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/alla-valda-aktiviteter/{genomforandereferens}`,
data: { genomforandereferens },
method: 'GemensamPlaneringApiService.fetchAllChosenActivities$',
});
})
);
}
public postGemensamPlanering$(data: GemensamPlaneringPostRequest): Observable<void> {
return this.httpClient.post<void>(`${this._apiBaseUrl}`, data).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Gemensam planering.\n\n${error.message}`,
name: `POST ${this._apiBaseUrl}`,
data,
method: 'GemensamPlaneringApiService.postGemensamPlanering$',
});
})
);
}
constructor(private httpClient: HttpClient) {}
}

View File

@@ -3,7 +3,7 @@ import { Injectable } from '@angular/core';
import { environment } from '@msfa-environment';
import { HandledareResponse } from '@msfa-models/api/handledare.response.model';
import { Params } from '@msfa-models/api/params.model';
import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error';
import { CustomError } from '@msfa-models/error/custom-error';
import { Handledare, mapHandledareResponseToHandledare } from '@msfa-models/handledare.model';
import { Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@@ -24,9 +24,13 @@ export class HandledareApiService {
.pipe(
map(({ data }) => data.map(handledare => mapHandledareResponseToHandledare(handledare))),
catchError((error: Error) => {
throw new CustomError(
errorToCustomError({ ...error, message: `Kunde inte hämta handledare.\n\n${error.message}` })
);
throw new CustomError({
error,
message: `Kunde inte hämta handledare.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}`,
data: { avropIds },
method: 'HandledareApiService.fetchAvailableHandledare$',
});
})
);
}
@@ -36,8 +40,20 @@ export class HandledareApiService {
avropIds,
ciamUserId: handledare.ciamUserId,
};
const apiUrl = `${this._apiBaseUrl}/assign`;
return this.httpClient
.patch<void>(`${this._apiBaseUrl}/assign`, null, { params })
.patch<void>(apiUrl, null, { params })
.pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte tilldela handledare.\n\n${error.message}`,
name: `PATCH ${apiUrl}`,
data: params,
method: 'HandledareApiService.assignHandledare',
});
})
)
.toPromise();
}
}

View File

@@ -5,9 +5,12 @@ import { AvvikelseReportResponse } from '@msfa-models/api/avvikelse-response.mod
import { FranvaroReportResponse } from '@msfa-models/api/franvaro-response.model';
import { GemensamPlaneringResponse } from '@msfa-models/api/gemensam-planering.response.model';
import { InformativRapportResponse } from '@msfa-models/api/informativ-rapport.response.model';
import { SlutredovisningResponse } from '@msfa-models/api/slutredovisning.response.model';
import { Observable } from 'rxjs';
import { PeriodiskRedovisningResponse } from '@msfa-models/api/periodisk-redovisning.response.model';
import { SignalResponse } from '@msfa-models/api/signal.response.model';
import { SlutredovisningResponse } from '@msfa-models/api/slutredovisning.response.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
@@ -18,29 +21,107 @@ export class HandlingarApiService {
constructor(private httpClient: HttpClient) {}
public fetchGemensamPlanering$(handlingId: string): Observable<{ data: GemensamPlaneringResponse }> {
return this.httpClient.get<{ data: GemensamPlaneringResponse }>(
`${this._apiBaseUrl}/gemensam-planering/${handlingId}`
return this.httpClient
.get<{ data: GemensamPlaneringResponse }>(`${this._apiBaseUrl}/gemensam-planering/${handlingId}`)
.pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Gemensam planering.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/gemensam-planering/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchGemensamPlanering$',
});
})
);
}
public fetchPeriodiskRedovisning$(handlingId: string): Observable<{ data: PeriodiskRedovisningResponse }> {
return this.httpClient
.get<{ data: PeriodiskRedovisningResponse }>(`${this._apiBaseUrl}/periodisk-redovisning/${handlingId}`)
.pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Periodisk redovisning.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/periodisk-redovisning/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchPeriodiskRedovisning$',
});
})
);
}
public fetchInformativRapport$(handlingId: string): Observable<{ data: InformativRapportResponse }> {
return this.httpClient.get<{ data: InformativRapportResponse }>(
`${this._apiBaseUrl}/informativ-rapport/${handlingId}`
return this.httpClient
.get<{ data: InformativRapportResponse }>(`${this._apiBaseUrl}/informativ-rapport/${handlingId}`)
.pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Informativ rapport.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/informativ-rapport/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchInformativRapport$',
});
})
);
}
public fetchSignal$(handlingId: string): Observable<{ data: SignalResponse }> {
return this.httpClient.get<{ data: SignalResponse }>(`${this._apiBaseUrl}/signal/${handlingId}`);
return this.httpClient.get<{ data: SignalResponse }>(`${this._apiBaseUrl}/signal/${handlingId}`).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Signal om arbete eller studier.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/signal/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchSignal$',
});
})
);
}
public fetchFranvaroReport$(handlingId: string): Observable<{ data: FranvaroReportResponse }> {
return this.httpClient.get<{ data: FranvaroReportResponse }>(`${this._apiBaseUrl}/franvaro/${handlingId}`);
return this.httpClient.get<{ data: FranvaroReportResponse }>(`${this._apiBaseUrl}/franvaro/${handlingId}`).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Avvikelserapport (frånvaro).\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/franvaro/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchFranvaroReport$',
});
})
);
}
public fetchAvvikelseReport$(handlingId: string): Observable<{ data: AvvikelseReportResponse }> {
return this.httpClient.get<{ data: AvvikelseReportResponse }>(`${this._apiBaseUrl}/avvikelse/${handlingId}`);
return this.httpClient.get<{ data: AvvikelseReportResponse }>(`${this._apiBaseUrl}/avvikelse/${handlingId}`).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Avvikelserapport (avvikelse).\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/avvikelse/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchAvvikelseReport$',
});
})
);
}
public fetchSlutredovisning$(handlingId: string): Observable<{ data: SlutredovisningResponse }> {
return this.httpClient.get<{ data: SlutredovisningResponse }>(`${this._apiBaseUrl}/slutredovisning/${handlingId}`);
return this.httpClient
.get<{ data: SlutredovisningResponse }>(`${this._apiBaseUrl}/slutredovisning/${handlingId}`)
.pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta Slutredovisning.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}/slutredovisning/{handlingId}`,
data: { handlingId },
method: 'HandlingarApiService.fetchSlutredovisning$',
});
})
);
}
}

View File

@@ -1,6 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { InformativRapportRequest } from '@msfa-models/api/informativ-rapport.request.model';
import { CustomError } from '@msfa-models/error/custom-error';
@@ -13,17 +12,19 @@ import { catchError } from 'rxjs/operators';
export class InformativRapportApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter/informativ-rapport`;
public postInformativRapport$(requestData: InformativRapportRequest): Observable<void> {
return this.httpClient.post<void>(this._apiBaseUrl, requestData).pipe(
constructor(private httpClient: HttpClient) {}
public postInformativRapport$(data: InformativRapportRequest): Observable<void> {
return this.httpClient.post<void>(this._apiBaseUrl, data).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Informativ rapport.\n\n${error.message}`,
type: ErrorType.API,
name: `POST ${this._apiBaseUrl}`,
data,
method: 'InformativRapportApiService.postInformativRapport$',
});
})
);
}
constructor(private httpClient: HttpClient) {}
}

View File

@@ -1,10 +1,8 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { NewsResponse } from '@msfa-models/api/news.response.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { ErrorService } from '@msfa-services/error.service';
import { Observable } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
@@ -14,19 +12,18 @@ import { catchError, map } from 'rxjs/operators';
export class NewsApiService {
private _apiBaseUrl = `${environment.api.url}/confluence/nyheter`;
constructor(private http: HttpClient, private errorService: ErrorService) {}
constructor(private http: HttpClient) {}
public fetchNews$(): Observable<NewsResponse> {
return this.http.get<{ data: NewsResponse }>(this._apiBaseUrl).pipe(
map(({ data }) => data),
catchError((error: Error) => {
const customError = new CustomError({
throw new CustomError({
error,
message: `Kunde inte hämta nyheter.\n\n${error.message}`,
type: ErrorType.API,
name: `GET ${this._apiBaseUrl}`,
method: 'NewsApiService.fetchNews$',
});
this.errorService.add(customError);
throw customError;
})
);
}

View File

@@ -1,9 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { PeriodiskRedovisningRequest } from '@msfa-models/api/periodisk-redovisning.request.model';
import { PeriodiskRedovisningResponse } from '@msfa-models/api/periodisk-redovisning.response.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
@@ -14,23 +12,17 @@ import { catchError } from 'rxjs/operators';
export class PeriodiskRedovisningApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter/periodisk-redovisning`;
private _handlingarBaseUrl = `${environment.api.url}/handlingar`;
constructor(private httpClient: HttpClient) {}
public fetchPeriodiskRedovisning$(handlingId: string): Observable<{ data: PeriodiskRedovisningResponse }> {
return this.httpClient.get<{ data: PeriodiskRedovisningResponse }>(
`${this._handlingarBaseUrl}/periodisk-redovisning/${handlingId}`
);
}
public postPeriodiskRedovisning$(requestData: PeriodiskRedovisningRequest): Observable<void> {
return this.httpClient.post<void>(`${this._apiBaseUrl}`, requestData).pipe(
public postPeriodiskRedovisning$(data: PeriodiskRedovisningRequest): Observable<void> {
return this.httpClient.post<void>(this._apiBaseUrl, data).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Periodisk redovisning.\n\n${error.message}`,
type: ErrorType.API,
name: `POST ${this._apiBaseUrl}`,
data,
method: 'PeriodiskRedovisningApiService.postPeriodiskRedovisning$',
});
})
);

View File

@@ -1,6 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { SignalRequest } from '@msfa-models/api/signal.request.model';
import { CustomError } from '@msfa-models/error/custom-error';
@@ -13,13 +12,15 @@ import { catchError } from 'rxjs/operators';
export class SignalApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter/signal`;
public postSignal$(requestData: SignalRequest): Observable<void> {
return this.httpClient.post<void>(this._apiBaseUrl, requestData).pipe(
public postSignal$(data: SignalRequest): Observable<void> {
return this.httpClient.post<void>(this._apiBaseUrl, data).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Signal om arbete eller studier.\n\n${error.message}`,
type: ErrorType.API,
name: `POST ${this._apiBaseUrl}`,
data,
method: 'SignalApiService.postSignal$',
});
})
);

View File

@@ -1,10 +1,8 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { YRKEN } from '@msfa-constants/yrken';
import { ErrorType } from '@msfa-enums/error-type.enum';
import { environment } from '@msfa-environment';
import { SlutredovisningRequest } from '@msfa-models/api/slutredovisning.request.model';
import { SlutredovisningResponse } from '@msfa-models/api/slutredovisning.response.model';
import { YrkesomradeResponse } from '@msfa-models/api/yrkesomrade.response.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Observable, of } from 'rxjs';
@@ -15,37 +13,35 @@ import { catchError } from 'rxjs/operators';
})
export class SlutredovisningApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter`;
private _handlingarBaseUrl = `${environment.api.url}/handlingar`;
constructor(private httpClient: HttpClient) {}
public fetchYrken$(): Observable<{ data: YrkesomradeResponse[] }> {
return of({ data: YRKEN });
// TODO: Whenever the taxonomy endpoint is implemented correctly in IPF then this should be implemented instead.
// return this.httpClient.get<{ data: YrkesomradeResponse[] }>(`${this._apiBaseUrl}/yrkesomraden`).pipe(
// const apiUrl = `${this._apiBaseUrl}/yrkesomraden`;
// return this.httpClient.get<{ data: YrkesomradeResponse[] }>(apiUrl).pipe(
// catchError((error: Error) => {
// throw new CustomError({
// error,
// message: `Kunde inte hämta yrkesområden och yrkesgrupper.\n\n${error.message}`,
// type: ErrorType.API,
// name: `GET ${apiUrl}`,
// method: 'SlutredovisningApiService.fetchYrken$',
// });
// })
// );
}
public fetchSlutredovisning$(handlingId: string): Observable<{ data: SlutredovisningResponse }> {
return this.httpClient.get<{ data: SlutredovisningResponse }>(
`${this._handlingarBaseUrl}/slutredovisning/${handlingId}`
);
}
public submitSlutredovisning$(requestData: SlutredovisningRequest): Observable<void> {
return this.httpClient.post<void>(`${this._apiBaseUrl}/slutredovisning`, requestData).pipe(
public submitSlutredovisning$(data: SlutredovisningRequest): Observable<void> {
const apiUrl = `${this._apiBaseUrl}/slutredovisning`;
return this.httpClient.post<void>(apiUrl, data).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Periodisk redovisning.\n\n${error.message}`,
type: ErrorType.API,
name: `POST ${apiUrl}`,
data,
method: 'SlutredovisningApiService.submitSlutredovisning$',
});
})
);

View File

@@ -0,0 +1,30 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@msfa-environment';
import { TjanstResponse } from '@msfa-models/api/tjanst.response.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Observable } from 'rxjs';
import { catchError, shareReplay } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class TjanstApiService {
private _apiBaseUrl = `${environment.api.url}/tjanster`;
constructor(private httpClient: HttpClient) {}
public fetchTjanster$(): Observable<{ data: TjanstResponse[] }> {
return this.httpClient.get<{ data: TjanstResponse[] }>(this._apiBaseUrl).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta tjänster.\n\n${error.message}`,
name: `GET ${this._apiBaseUrl}`,
method: 'TjanstApiService.fetchTjanster$',
});
}),
shareReplay(1)
);
}
}

View File

@@ -1,36 +0,0 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
import { environment } from '@msfa-environment';
import { TjanstResponse } from '@msfa-models/api/tjanst.response.model';
import { mapResponseToTjanst, Tjanst } from '@msfa-models/tjanst.model';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter, map, switchMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class TjanstService extends UnsubscribeDirective {
private _apiBaseUrl = `${environment.api.url}/tjanster`;
private _tjanster$ = new BehaviorSubject<Tjanst[]>(null);
public tjanster$: Observable<Tjanst[]> = this._tjanster$.asObservable();
private _fetchTjanster$: Observable<Tjanst[]> = this.tjanster$.pipe(
filter(tjanster => !tjanster?.length),
switchMap(() =>
this.httpClient
.get<{ data: TjanstResponse[] }>(this._apiBaseUrl)
.pipe(map(({ data }) => data.map(tjanst => mapResponseToTjanst(tjanst))))
)
);
constructor(private httpClient: HttpClient) {
super();
super.unsubscribeOnDestroy(
this._fetchTjanster$.subscribe(tjanster => {
this._tjanster$.next(tjanster);
})
);
}
}

View File

@@ -0,0 +1,45 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { environment } from '@msfa-environment';
import { EmployeeResponse } from '@msfa-models/api/employee.response.model';
import { OrganizationResponse } from '@msfa-models/api/organization.response.model';
import { CustomError } from '@msfa-models/error/custom-error';
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class UserApiService {
private _apiAuthUrl = `${environment.api.url}/auth`;
private _apiUserUrl = `${environment.api.url}/users/currentUser`;
constructor(private httpClient: HttpClient) {}
public fetchOrganizations$(): Observable<{ data: OrganizationResponse[] }> {
const apiUrl = `${this._apiAuthUrl}/organizations`;
return this.httpClient.get<{ data: OrganizationResponse[] }>(apiUrl).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta organisationer.\n\n${error.message}`,
name: `GET ${apiUrl}`,
method: 'UserApiService.fetchOrganizations$',
});
})
);
}
public fetchCurrentUser$(): Observable<{ data: EmployeeResponse }> {
return this.httpClient.get<{ data: EmployeeResponse }>(this._apiUserUrl).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte hämta användarinformation.\n\n${error.message}`,
name: `GET ${this._apiUserUrl}`,
method: 'UserApiService.fetchCurrentUser$',
});
})
);
}
}

View File

@@ -1,118 +0,0 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ApmService } from '@elastic/apm-rum-angular';
import { SELECTED_ORGANIZATION_NUMBER_KEY } from '@msfa-constants/local-storage-keys';
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
import { environment } from '@msfa-environment';
import { EmployeeResponse } from '@msfa-models/api/employee.response.model';
import { OrganizationResponse } from '@msfa-models/api/organization.response.model';
import { UserInfoResponse } from '@msfa-models/api/user-info.response.model';
import { Employee, mapResponseToEmployee } from '@msfa-models/employee.model';
import { mapResponseToOrganization, Organization } from '@msfa-models/organization.model';
import { Role } from '@msfa-models/role.model';
import { mapResponseToUserInfo, UserInfo } from '@msfa-models/user-info.model';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { filter, map, switchMap, tap } from 'rxjs/operators';
import { AuthenticationService } from './authentication.service';
@Injectable({
providedIn: 'root',
})
export class UserService extends UnsubscribeDirective {
private _apiAuthUrl = `${environment.api.url}/auth`;
private _apiUserUrl = `${environment.api.url}/users/currentUser`;
private _isLoggedIn$: Observable<boolean> = this.authenticationService.isLoggedIn$;
private _organizations$ = new BehaviorSubject<Organization[]>(null);
public organizations$: Observable<Organization[]> = this._organizations$.asObservable();
private _user$ = new BehaviorSubject<Employee>(null);
public user$: Observable<Employee> = this._user$.asObservable();
private _userRolesLoading$ = new BehaviorSubject<boolean>(false);
public userRolesLoading$: Observable<boolean> = this._userRolesLoading$.asObservable();
private _userLoading$ = new BehaviorSubject<boolean>(false);
public userLoading$: Observable<boolean> = this._userLoading$.asObservable();
private _userRoles$ = new BehaviorSubject<Role[]>(null);
public userRoles$: Observable<Role[]> = this._userRoles$.asObservable();
private _selectedOrganizationNumber$ = new BehaviorSubject<string>(null);
public get userRolesSnapshot(): Role[] {
return this._userRoles$.getValue();
}
constructor(
private httpClient: HttpClient,
private authenticationService: AuthenticationService,
private apmService: ApmService
) {
super();
this._selectedOrganizationNumber$.next(this._selectedOrganizationNumber);
super.unsubscribeOnDestroy(
this._isLoggedIn$
.pipe(
filter(loggedIn => !!loggedIn),
switchMap(() => this._fetchOrganizations$())
)
.subscribe(organizations => {
this._organizations$.next(organizations);
}),
combineLatest([this._isLoggedIn$, this.selectedOrganization$])
.pipe(
filter(([loggedIn, selectedOrganization]) => !!(loggedIn && selectedOrganization)),
tap(() => {
this._userLoading$.next(true);
this._userRolesLoading$.next(true);
}),
switchMap(() => combineLatest([this._fetchUserInfo$(), this._fetchCurrentUser$()]))
)
.subscribe(([userInfo, currentUser]) => {
this._userRoles$.next(userInfo.roles);
this._user$.next(currentUser);
this._userLoading$.next(false);
this._userRolesLoading$.next(false);
this.apmService.apm.setUserContext({ id: currentUser.id });
})
);
}
private _fetchOrganizations$(): Observable<Organization[]> {
return this.httpClient.get<{ data: OrganizationResponse[] }>(`${this._apiAuthUrl}/organizations`).pipe(
filter(response => !!response?.data),
map(({ data }) => data.map(organization => mapResponseToOrganization(organization)))
);
}
private _fetchUserInfo$(): Observable<UserInfo> {
return this.httpClient.get<{ data: UserInfoResponse }>(`${this._apiAuthUrl}/userinfo`).pipe(
filter(response => !!response?.data),
map(({ data }) => mapResponseToUserInfo(data))
);
}
private _fetchCurrentUser$(): Observable<Employee> {
return this.httpClient.get<{ data: EmployeeResponse }>(`${this._apiUserUrl}`).pipe(
filter(response => !!response?.data),
map(({ data }) => mapResponseToEmployee(data))
);
}
private get _selectedOrganizationNumber(): string | null {
return localStorage.getItem(SELECTED_ORGANIZATION_NUMBER_KEY);
}
public get selectedOrganization$(): Observable<Organization | null> {
return combineLatest([this._selectedOrganizationNumber$, this._organizations$]).pipe(
filter(([, organizations]) => !!organizations?.length),
map(([organizationNumber, organizations]) => {
return organizationNumber
? organizations.find(organization => organization.organizationNumber === organizationNumber)
: null;
})
);
}
public setSelectedOrganization(organization: Organization): void {
localStorage.setItem(SELECTED_ORGANIZATION_NUMBER_KEY, organization.organizationNumber);
this._selectedOrganizationNumber$.next(organization.organizationNumber);
}
}

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { AvropParams, Params } from '@msfa-models/api/params.model';
import { Avrop, AvropAndMeta } from '@msfa-models/avrop.model';
import { Handledare } from '@msfa-models/handledare.model';
import { AvropApiService } from '@msfa-services/api/avrop-api.service';
import { AvropApiService } from '@msfa-services/api/avrop.api.service';
import { MultiselectFilterOption } from '@ui/multiselect/multiselect-filter-option';
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
import { distinctUntilChanged, filter, map, shareReplay, switchMap, tap } from 'rxjs/operators';

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { PaginationParams } from '@msfa-models/api/params.model';
import { BehaviorSubject, combineLatest } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { DeltagareHandelserApiService } from './api/deltagare-handelser-api.service';
import { DeltagareHandelserApiService } from './api/deltagare-handelser.api.service';
const DEFAULT_PARAMS: PaginationParams = {
page: 1,

View File

@@ -1,5 +1,4 @@
import { Injectable } from '@angular/core';
import { errorToCustomError } from '@msfa-models/error/custom-error';
import { Handledare } from '@msfa-models/handledare.model';
import { BehaviorSubject, Observable } from 'rxjs';
import { HandledareApiService } from './api/handledare.api.service';
@@ -31,11 +30,6 @@ export class HandledareService {
.then(() => {
this._lastSavedHandledare$.next(handledare);
})
.catch((error: Error) => {
this.errorService.add(
errorToCustomError({ ...error, message: `Kunde inte tilldela handledare.\n\n${error.message}` })
);
})
.finally(() => {
this._submitHandledareLoading$.next(false);
});

View File

@@ -1,13 +1,11 @@
import { Injectable } from '@angular/core';
import { RoleEnum } from '@msfa-enums/role.enum';
import { environment } from '@msfa-environment';
import { mapResponseToRoles, Role } from '@msfa-models/role.model';
@Injectable({
providedIn: 'root',
})
export class RoleService {
private readonly _apiBaseUrl = `${environment.api.url}/auth/userinfo`;
public get allRoles(): Role[] {
return mapResponseToRoles(Object.keys(RoleEnum) as RoleEnum[]);
}

View File

@@ -0,0 +1,74 @@
import { Injectable } from '@angular/core';
import { ApmService } from '@elastic/apm-rum-angular';
import { SELECTED_ORGANIZATION_NUMBER_KEY } from '@msfa-constants/local-storage-keys';
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
import { Employee, mapResponseToEmployee } from '@msfa-models/employee.model';
import { mapResponseToOrganization, Organization } from '@msfa-models/organization.model';
import { mapResponseToRoles, Role } from '@msfa-models/role.model';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { filter, map, mapTo, shareReplay, startWith, switchMap } from 'rxjs/operators';
import { AuthenticationService } from './api/authentication.service';
import { UserApiService } from './api/user.api.service';
@Injectable({
providedIn: 'root',
})
export class UserService extends UnsubscribeDirective {
private _isLoggedIn$: Observable<boolean> = this.authenticationService.isLoggedIn$;
private _selectedOrganizationNumber$ = new BehaviorSubject<string | null>(null);
public organizations$: Observable<Organization[]> = this._isLoggedIn$.pipe(
filter(loggedIn => !!loggedIn),
switchMap(() =>
this.userApiService
.fetchOrganizations$()
.pipe(map(({ data }) => data.map(organization => mapResponseToOrganization(organization))))
),
shareReplay(1)
);
public selectedOrganization$: Observable<Organization | null> = combineLatest([
this.organizations$,
this._selectedOrganizationNumber$,
]).pipe(
filter(([organizations]) => !!organizations?.length),
map(([organizations, organizationNumber]) => {
return organizationNumber
? organizations.find(organization => organization.organizationNumber === organizationNumber)
: null;
})
);
public user$: Observable<Employee> = combineLatest([this._isLoggedIn$, this.selectedOrganization$]).pipe(
filter(([loggedIn, selectedOrganization]) => !!(loggedIn && selectedOrganization)),
switchMap(() => this.userApiService.fetchCurrentUser$().pipe(map(({ data }) => mapResponseToEmployee(data)))),
shareReplay(1)
);
public userRoles$: Observable<Role[]> = this.user$.pipe(map(({ roles }) => mapResponseToRoles(roles)));
public userLoading$: Observable<boolean> = combineLatest([this._isLoggedIn$, this.selectedOrganization$]).pipe(
filter(([isLoggedIn, selectedOrganization]) => !!(isLoggedIn && selectedOrganization)),
switchMap(() => this.user$.pipe(mapTo(false), startWith(true))),
startWith(false)
);
constructor(
private authenticationService: AuthenticationService,
private userApiService: UserApiService,
private apmService: ApmService
) {
super();
this._setSelectedOrganizationNumberFromLocalStorage();
super.unsubscribeOnDestroy(
this.user$.subscribe(user => {
this.apmService.apm.setUserContext({ id: user.id });
})
);
}
private _setSelectedOrganizationNumberFromLocalStorage(): void {
this._selectedOrganizationNumber$.next(localStorage.getItem(SELECTED_ORGANIZATION_NUMBER_KEY));
}
public setSelectedOrganization(organization: Organization): void {
localStorage.setItem(SELECTED_ORGANIZATION_NUMBER_KEY, organization.organizationNumber);
this._selectedOrganizationNumber$.next(organization.organizationNumber);
}
}