Merge branch 'develop' of ssh://bitbucket.arbetsformedlingen.se:7999/tea/mina-sidor-fa-web into develop

This commit is contained in:
Erik Tiekstra
2021-11-12 09:31:05 +01:00
105 changed files with 5624 additions and 44 deletions

View File

@@ -1,34 +1,14 @@
<div class="error-list-wrapper" [hidden]="!validationErrorLinks || validationErrorLinks.length === 0">
<digi-notification-alert
class="error-list"
af-variation="danger"
[attr.af-heading]="headingText"
[af-heading-level]="headingLevel"
[afCloseable]="false"
<digi-form-error-list
*ngIf="validationErrorLinks && validationErrorLinks.length"
[afHeading]="headingText"
[afOverrideLink]="true"
(afOnClickLink)="setFocusOnFormElement($event.detail.detail.target)"
>
<a
msfaAnchorLink
*ngFor="let validationErrorLink of validationErrorLinks"
[attr.href]="'#' + validationErrorLink.elementId"
>
<ul class="error-list__validation-error-links">
<li *ngFor="let validationErrorLink of validationErrorLinks;">
<digi-ng-link-internal
msfaAnchorLink
class="error-list__validation-error-link"
[afHref]="'#' + validationErrorLink.elementId"
[afText]="validationErrorLink.text"
></digi-ng-link-internal>
</li>
</ul>
</digi-notification-alert>
</div>
<!-- <digi-form-error-list
class="edit-employee-form__validation-error-summary"
af-heading="Åtgärda följande fel för att spara dina ändringar:"
*ngIf="validationErrorLinks && validationErrorLinks.length !== 0"
>
Behöver hantera ankarlänkar kopplat till den här komponenten om det ska fungera att använda den...
<a
[attr.href]="'#' + validationErrorLink.elementId"
[attr.id]="first ? firstValidationErrorLinkId : 'validation-error-link-' + index"
*ngFor="let validationErrorLink of validationErrorLinks; let first = first; let index = index"
>
{{ validationErrorLink.text }}
</a>
</digi-form-error-list> -->
{{ validationErrorLink.text }}
</a>
</digi-form-error-list>

View File

@@ -1,5 +1,5 @@
import { TypographyDynamicHeadingLevel } from '@af/digi-ng/_typography/typography-dynamic-heading';
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
export interface ValidationErrorLink {
elementId: string;
@@ -16,4 +16,22 @@ export class ErrorListComponent {
@Input() validationErrorLinks: ValidationErrorLink[] = [];
@Input() headingText: string;
@Input() headingLevel: TypographyDynamicHeadingLevel = TypographyDynamicHeadingLevel.H3;
setFocusOnFormElement(element: HTMLElement): void {
const id = element.getAttribute('href').replace('#', '');
const target = document.getElementById(id);
if (target) {
const targetPosition: DOMRect = target.getBoundingClientRect();
const absoluteElementPosition = targetPosition.top + window.scrollY;
const newPosition = absoluteElementPosition - window.innerHeight / 2;
if (target.focus) {
target.tabIndex = -1;
target.focus();
window.scrollTo(0, newPosition);
target.tabIndex = 0;
}
}
}
}

View File

@@ -5,6 +5,7 @@ export const DELTAGARE_REPORTING_ROUTES = {
avvikelserapport: 'Avvikelserapport (avvikelse)',
signal: 'Signal om arbete eller studier',
'informativ-rapport': 'Informativ rapport',
slutredovisning: 'Slutredovisning',
};
export const NAVIGATION = {

File diff suppressed because it is too large Load Diff

View File

@@ -12,13 +12,17 @@ export class AnchorLinkDirective {
const elementId = href?.trim().replace('#', '');
const element = document.getElementById(elementId);
if (element && element.focus) {
element.tabIndex = -1;
element.focus();
}
if (element) {
const elementPosition: DOMRect = element.getBoundingClientRect();
const absoluteElementPosition = elementPosition.top + window.scrollY;
const newPosition = absoluteElementPosition - window.innerHeight / 2;
if (element.tabIndex < 0) {
element.scrollIntoView();
if (element.focus) {
element.tabIndex = -1;
element.focus();
window.scrollTo(0, newPosition);
element.tabIndex = 0;
}
}
event.stopPropagation();

View File

@@ -16,5 +16,6 @@ export enum Feature {
REPORTING_PERIODISK_REDOVISNING,
REPORTING_INFORMATIV_RAPPORT,
EXPORTS,
SLUTREDOVISNING,
NEWS,
}

View File

@@ -5,6 +5,7 @@ export enum ReportType {
Avvikelse = 'Avvikelserapport (avvikelse)',
Franvaro = 'Avvikelserapport (frånvaro)',
PeriodiskRedovisning = 'Periodisk redovisning',
Slutredovisning = 'Slutredovisning',
InformativRapport = 'Informativ rapport',
InformativRedovisning = 'Informativ rapport',
}

View File

@@ -0,0 +1,68 @@
import {
Anstallningsform,
EducationLength,
EducationLevel,
MainOccupation,
Omfattning,
StillUnemployedReason,
} from '@msfa-models/slutredovisning.model';
export interface SlutredovisningRequestMainOccupationWorkDetails {
yrkesomrade: string;
yrkesgrupp: string;
anstallningsform: Anstallningsform;
otherExplanation: string;
omfattning: Omfattning;
omfattningPercent: number;
}
export interface SlutredovisningRequestMainOccupationWork {
type: MainOccupation.Work;
work: SlutredovisningRequestMainOccupationWorkDetails[];
}
export interface SlutredovisningRequestMainOccupationEducationDetails {
educationLevel: EducationLevel;
otherExplanation: string;
educationLength: EducationLength;
educationSpecification: string;
}
export interface SlutredovisningRequestMainOccupationEducation {
type: MainOccupation.Education;
education: SlutredovisningRequestMainOccupationEducationDetails;
}
export interface SlutredovisningRequestMainOccupationOtherDetails {
otherExplanation: string;
}
export interface SlutredovisningRequestMainOccupationOther {
type: MainOccupation.Other;
other: SlutredovisningRequestMainOccupationOtherDetails;
}
export interface SlutredovisningRequestMainOccupationStillUnemployedDetails {
reasonsGoalNotReached: StillUnemployedReason[];
otherExplanation: string;
}
export interface SlutredovisningRequestMainOccupationStillUnemployed {
type: MainOccupation.StillUnemployed;
stillUnemployed: SlutredovisningRequestMainOccupationStillUnemployedDetails;
}
export type SlutredovisningRequestMainOccupationDetails =
| SlutredovisningRequestMainOccupationWork
| SlutredovisningRequestMainOccupationEducation
| SlutredovisningRequestMainOccupationOther
| SlutredovisningRequestMainOccupationStillUnemployed;
export interface SlutredovisningRequest {
genomforandereferens: number;
mainOccupation: SlutredovisningRequestMainOccupationDetails;
activities: { id: string; whatHasBeenDone: string }[];
progressDescription: string;
nextStepDescription: string;
otherInformation: string;
}

View File

@@ -0,0 +1,70 @@
import {
Anstallningsform,
EducationLength,
EducationLevel,
MainOccupation,
Omfattning,
StillUnemployedReason,
} from '@msfa-models/slutredovisning.model';
export interface SlutredovisningResponseMainOccupationWorkDetails {
yrkesomrade: string;
yrkesgrupp: string;
yrkesomradeName: string;
yrkesgruppName: string;
anstallningsform: Anstallningsform;
otherExplanation: string;
omfattning: Omfattning;
omfattningPercent: number;
}
export interface SlutredovisningResponseMainOccupationWork {
type: MainOccupation.Work;
work: SlutredovisningResponseMainOccupationWorkDetails[];
}
export interface SlutredovisningResponseMainOccupationEducationDetails {
educationLevel: EducationLevel;
otherExplanation: string;
educationLength: EducationLength;
educationSpecification: string;
}
export interface SlutredovisningResponseMainOccupationEducation {
type: MainOccupation.Education;
education: SlutredovisningResponseMainOccupationEducationDetails;
}
export interface SlutredovisningResponseMainOccupationOtherDetails {
otherExplanation: string;
}
export interface SlutredovisningResponseMainOccupationOther {
type: MainOccupation.Other;
other: SlutredovisningResponseMainOccupationOtherDetails;
}
export interface SlutredovisningResponseMainOccupationStillUnemployedDetails {
reasonsGoalNotReached: StillUnemployedReason[];
otherExplanation: string;
}
export interface SlutredovisningResponseMainOccupationStillUnemployed {
type: MainOccupation.StillUnemployed;
stillUnemployed: SlutredovisningResponseMainOccupationStillUnemployedDetails;
}
export type SlutredovisningResponseMainOccupationDetails =
| SlutredovisningResponseMainOccupationWork
| SlutredovisningResponseMainOccupationEducation
| SlutredovisningResponseMainOccupationOther
| SlutredovisningResponseMainOccupationStillUnemployed;
export interface SlutredovisningResponse {
genomforandereferens: number;
mainOccupation: SlutredovisningResponseMainOccupationDetails;
activities: { id: string; whatHasBeenDone: string; name: string }[];
progressDescription: string;
nextStepDescription: string;
otherInformation: string;
}

View File

@@ -0,0 +1,5 @@
export interface YrkesgruppResponse {
id: string;
name: string;
parentId: string;
}

View File

@@ -0,0 +1,7 @@
import { YrkesgruppResponse } from './yrkesgrupp.response.model';
export interface YrkesomradeResponse {
id: string;
name: string;
items: YrkesgruppResponse[];
}

View File

@@ -0,0 +1,108 @@
import { SlutredovisningResponse } from '@msfa-models/api/slutredovisning.response.model';
export enum MainOccupation {
Work = 'work',
Education = 'education',
StillUnemployed = 'stillUnemployed',
ByteTillNyLeverantorIRustaOchMatcha = 'byte till ny leverantör i rusta och matcha',
Other = 'other',
}
export enum EducationLevel {
HogskolaEllerUniversitet = 'högskola eller universitet',
Yrkeshogskola = 'yrkeshögskola',
KomvuxGymnasiumFolkhogskola = 'komvux, gymnasium eller folkhögskola',
VetEj = 'vet ej',
Annat = 'annat',
}
export function educationLevelToString(educationLevel: EducationLevel): string | null {
switch (educationLevel) {
case EducationLevel.HogskolaEllerUniversitet:
return 'Högskola eller universitet';
case EducationLevel.Yrkeshogskola:
return 'Yrkeshögskola';
case EducationLevel.KomvuxGymnasiumFolkhogskola:
return 'Komvux, gymnasium eller folkhögskola';
case EducationLevel.VetEj:
return 'Vet ej';
case EducationLevel.Annat:
return 'Annat';
default:
return null;
}
}
export enum StillUnemployedReason {
SaknarRelevantUtbildning = 'saknar relevant utbildning',
SaknarArbetslivserfarenhet = 'saknar arbetslivserfarenhet',
SaknarNatverkOchKontakter = 'saknar nätverk och kontakter',
BristandeSprakkunskaperISvenska = 'bristande språkkunskaper i svenska',
KonjukturLaget = 'konjunkturläget',
Annat = 'annat',
}
export enum EducationLength {
UpToOneYear = 'upp till ett år',
OneToTwoYears = 'ett år till två år',
OverTwoYears = 'två år eller längre',
}
export function educationLengthToString(educationLength: EducationLength): string | null {
switch (educationLength) {
case EducationLength.UpToOneYear:
return 'Upp till ett år';
case EducationLength.OneToTwoYears:
return 'Ett år till två år';
case EducationLength.OverTwoYears:
return 'Två år eller längre';
default:
return null;
}
}
export enum Anstallningsform {
Tillsvidare = 'tillsvidareanställning',
Prov = 'provanstallning',
Visstid = 'visstidsanställning',
VetEj = 'vet ej',
Annat = 'annat',
}
export enum Omfattning {
Heltid = 'heltid',
Deltid = 'deltid',
VetEj = 'vet ej',
}
export function omfattningToString(omfattning: Omfattning): string | null {
switch (omfattning) {
case Omfattning.Heltid:
return 'Heltid';
case Omfattning.Deltid:
return 'Deltid';
case Omfattning.VetEj:
return 'Vet ej';
default:
return null;
}
}
export type Slutredovisning = SlutredovisningResponse;
export function mainOccupationToString(mainOccupation: MainOccupation): string | null {
switch (mainOccupation) {
case MainOccupation.Education:
return 'Utbildning';
case MainOccupation.StillUnemployed:
return 'Fortsatt arbetssökande';
case MainOccupation.ByteTillNyLeverantorIRustaOchMatcha:
return 'Byte till ny leverantör i Rusta och matcha';
case MainOccupation.Other:
return 'Annat';
case MainOccupation.Work:
return 'Arbete';
default:
return null;
}
}

View File

@@ -0,0 +1,13 @@
import { YrkesgruppResponse } from './api/yrkesgrupp.response.model';
export interface Yrkesgrupp {
value: string;
name: string;
parentId: string;
}
export function mapResponseToYrkesgrupp(data: YrkesgruppResponse): Yrkesgrupp {
const { id, name, parentId } = data;
return { value: id, name, parentId };
}

View File

@@ -0,0 +1,26 @@
import { YrkesomradeResponse } from './api/yrkesomrade.response.model';
import { mapResponseToYrkesgrupp, Yrkesgrupp } from './yrkesgrupp.model';
export interface Yrkesomrade {
value: string;
name: string;
items: Yrkesgrupp[];
}
export function mapResponseToYrkesomrade(data: YrkesomradeResponse): Yrkesomrade {
const { id, name, items } = data;
return { value: id, name, items: items.map(item => mapResponseToYrkesgrupp(item)) };
}
export function yrkeToTextMap(yrkesomraden: Yrkesomrade[]): { [key: string]: string } {
const translateMap: { [key: string]: string } = {};
yrkesomraden.forEach(yrkesomrade => {
translateMap[yrkesomrade.value] = yrkesomrade.name;
yrkesomrade.items.forEach(yrkesgrupp => {
translateMap[yrkesgrupp.value] = yrkesgrupp.name;
});
});
return translateMap;
}

View File

@@ -6,6 +6,7 @@ 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 { Observable } from 'rxjs';
import { SlutredovisningResponse } from '@msfa-models/api/slutredovisning.response.model';
@Injectable({
providedIn: 'root',
@@ -34,4 +35,8 @@ export class HandlingarApiService {
public fetchAvvikelseReport$(handlingId: string): Observable<{ data: AvvikelseReportResponse }> {
return this.httpClient.get<{ data: AvvikelseReportResponse }>(`${this._apiBaseUrl}/avvikelse/${handlingId}`);
}
public fetchSlutredovisning$(handlingId: string) {
return this.httpClient.get<{ data: SlutredovisningResponse }>(`${this._apiBaseUrl}/slutredovisning/${handlingId}`);
}
}

View File

@@ -0,0 +1,43 @@
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';
import { catchError } from 'rxjs/operators';
@Injectable({
providedIn: 'root',
})
export class SlutredovisningApiService {
private _apiBaseUrl = `${environment.api.url}/rapporter/slutredovisning`;
private _handlingarBaseUrl = `${environment.api.url}/handlingar`;
constructor(private httpClient: HttpClient) {}
public fetchYrken$(): Observable<{ data: YrkesomradeResponse[] }> {
return of({ data: YRKEN });
}
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}`, requestData).pipe(
catchError((error: Error) => {
throw new CustomError({
error,
message: `Kunde inte spara Periodisk redovisning.\n\n${error.message}`,
type: ErrorType.API,
});
})
);
}
}

View File

@@ -0,0 +1,3 @@
export function capitalizeSentence(sentence: string): string {
return sentence.charAt(0).toUpperCase() + sentence.slice(1);
}