refactor(project): Renamed all instances of dafa to msfa or mina-sidor-fa. (TV-379)
Squashed commit of the following: commit d3f52ff6876f6e246c7d3c188e56cc2370289341 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Aug 17 14:10:38 2021 +0200 Renamed all dafa instances to msfa
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
<a class="back-link" [routerLink]="route">
|
||||
<msfa-icon [icon]="iconType.ARROW_LEFT"></msfa-icon>
|
||||
<ng-content></ng-content>
|
||||
</a>
|
||||
@@ -0,0 +1,11 @@
|
||||
.back-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
font-weight: var(--digi--typography--font-weight--semibold);
|
||||
gap: var(--digi--layout--gutter--xs);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* tslint:disable:no-unused-variable */
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { BackLinkComponent } from './back-link.component';
|
||||
|
||||
describe('BackLinkComponent', () => {
|
||||
let component: BackLinkComponent;
|
||||
let fixture: ComponentFixture<BackLinkComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [BackLinkComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(BackLinkComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-back-link',
|
||||
templateUrl: './back-link.component.html',
|
||||
styleUrls: ['./back-link.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BackLinkComponent {
|
||||
@Input() route: string[];
|
||||
iconType = IconType;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IconModule } from '../icon/icon.module';
|
||||
import { BackLinkComponent } from './back-link.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [BackLinkComponent],
|
||||
imports: [CommonModule, RouterModule, IconModule],
|
||||
exports: [BackLinkComponent],
|
||||
})
|
||||
export class BackLinkModule {}
|
||||
@@ -0,0 +1,8 @@
|
||||
<span class="hide-text">
|
||||
{{ transformedText }}
|
||||
<button class="hide-text__button" type="button" [attr.aria-label]="ariaLabel" (click)="toggleText()">
|
||||
<msfa-icon *ngIf="!hideText" [icon]="iconType.EYESLASH" size="l"></msfa-icon>
|
||||
<msfa-icon *ngIf="hideText" [icon]="iconType.EYE" size="l"></msfa-icon>
|
||||
<span class="hide-text__button-text">{{ hideText ? 'Visa' : 'Dölj'}}</span>
|
||||
</button>
|
||||
</span>
|
||||
@@ -0,0 +1,22 @@
|
||||
.hide-text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--digi--layout--gutter);
|
||||
|
||||
&__button {
|
||||
background-color: transparent;
|
||||
color: var(--digi--typography--color--link);
|
||||
font-size: var(--digi--typography--font-size--desktop);
|
||||
border-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover {
|
||||
color: var(--digi--typography--color--link--active);
|
||||
}
|
||||
}
|
||||
|
||||
&__button-text {
|
||||
margin-left: var(--digi--layout--gutter--s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { HideTextComponent } from './hide-text.component';
|
||||
|
||||
describe('HideTextComponent', () => {
|
||||
let component: HideTextComponent;
|
||||
let fixture: ComponentFixture<HideTextComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [HideTextComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HideTextComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-hide-text',
|
||||
templateUrl: './hide-text.component.html',
|
||||
styleUrls: ['./hide-text.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class HideTextComponent {
|
||||
@Input() changingText: string;
|
||||
@Input() symbols: string;
|
||||
@Input() ariaLabelType = 'text';
|
||||
|
||||
hideText = true;
|
||||
iconType = IconType;
|
||||
|
||||
get transformedText(): string {
|
||||
return this.hideText ? this.symbols : this.changingText;
|
||||
}
|
||||
|
||||
toggleText(): void {
|
||||
this.hideText = !this.hideText;
|
||||
}
|
||||
|
||||
get ariaLabel(): string {
|
||||
const buttonText = this.hideText ? 'Visa' : 'Dölj';
|
||||
return `${buttonText} ${this.ariaLabelType}`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { HideTextComponent } from './hide-text.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [HideTextComponent],
|
||||
imports: [CommonModule, IconModule],
|
||||
exports: [HideTextComponent],
|
||||
})
|
||||
export class HideTextModule {}
|
||||
@@ -0,0 +1,63 @@
|
||||
<digi-ng-icon-custom *ngIf="isCustomIcon; else DigiNgIcon" aria-hidden="true" class="icon" [ngClass]="[iconClass]">
|
||||
<svg *ngIf="icon === iconType.HOME" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" width="25" height="25">
|
||||
<path
|
||||
d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
<svg
|
||||
*ngIf="icon === iconType.SETTINGS"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 512 512"
|
||||
width="25"
|
||||
height="25"
|
||||
>
|
||||
<path
|
||||
d="M487.4 315.7l-42.6-24.6c4.3-23.2 4.3-47 0-70.2l42.6-24.6c4.9-2.8 7.1-8.6 5.5-14-11.1-35.6-30-67.8-54.7-94.6-3.8-4.1-10-5.1-14.8-2.3L380.8 110c-17.9-15.4-38.5-27.3-60.8-35.1V25.8c0-5.6-3.9-10.5-9.4-11.7-36.7-8.2-74.3-7.8-109.2 0-5.5 1.2-9.4 6.1-9.4 11.7V75c-22.2 7.9-42.8 19.8-60.8 35.1L88.7 85.5c-4.9-2.8-11-1.9-14.8 2.3-24.7 26.7-43.6 58.9-54.7 94.6-1.7 5.4.6 11.2 5.5 14L67.3 221c-4.3 23.2-4.3 47 0 70.2l-42.6 24.6c-4.9 2.8-7.1 8.6-5.5 14 11.1 35.6 30 67.8 54.7 94.6 3.8 4.1 10 5.1 14.8 2.3l42.6-24.6c17.9 15.4 38.5 27.3 60.8 35.1v49.2c0 5.6 3.9 10.5 9.4 11.7 36.7 8.2 74.3 7.8 109.2 0 5.5-1.2 9.4-6.1 9.4-11.7v-49.2c22.2-7.9 42.8-19.8 60.8-35.1l42.6 24.6c4.9 2.8 11 1.9 14.8-2.3 24.7-26.7 43.6-58.9 54.7-94.6 1.5-5.5-.7-11.3-5.6-14.1zM256 336c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
<svg *ngIf="icon === iconType.PLUS" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="25" height="25">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
<svg
|
||||
*ngIf="icon === iconType.CLIPBOARD"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 384 512"
|
||||
width="25"
|
||||
height="25"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M384 112v352c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h80c0-35.29 28.71-64 64-64s64 28.71 64 64h80c26.51 0 48 21.49 48 48zM192 40c-13.255 0-24 10.745-24 24s10.745 24 24 24 24-10.745 24-24-10.745-24-24-24m96 114v-20a6 6 0 0 0-6-6H102a6 6 0 0 0-6 6v20a6 6 0 0 0 6 6h180a6 6 0 0 0 6-6z"
|
||||
></path>
|
||||
</svg>
|
||||
</digi-ng-icon-custom>
|
||||
|
||||
<ng-template #DigiNgIcon>
|
||||
<ng-container [ngSwitch]="icon">
|
||||
<digi-icon-user-alt *ngSwitchCase="iconType.USER" [ngClass]="iconClass"></digi-icon-user-alt>
|
||||
<digi-icon-users-solid *ngSwitchCase="iconType.USERS" [ngClass]="iconClass"></digi-icon-users-solid>
|
||||
<digi-icon-bell *ngSwitchCase="iconType.BELL" [ngClass]="iconClass"></digi-icon-bell>
|
||||
<digi-icon-calendar-alt *ngSwitchCase="iconType.CALENDAR" [ngClass]="iconClass"></digi-icon-calendar-alt>
|
||||
<digi-icon-envelope-filled *ngSwitchCase="iconType.ENVELOPE" [ngClass]="iconClass"></digi-icon-envelope-filled>
|
||||
<digi-icon-sokkandidat *ngSwitchCase="iconType.SOK_KANDIDAT" [ngClass]="iconClass"></digi-icon-sokkandidat>
|
||||
<digi-icon-edit *ngSwitchCase="iconType.EDIT" [ngClass]="iconClass"></digi-icon-edit>
|
||||
<digi-icon-exclamation-circle *ngSwitchCase="iconType.INFO" [ngClass]="iconClass"></digi-icon-exclamation-circle>
|
||||
<digi-icon-exclamation-triangle
|
||||
*ngSwitchCase="iconType.WARNING"
|
||||
[ngClass]="iconClass"
|
||||
></digi-icon-exclamation-triangle>
|
||||
<digi-icon-check-circle-reg *ngSwitchCase="iconType.APPROVED" [ngClass]="iconClass"></digi-icon-check-circle-reg>
|
||||
<digi-icon-x *ngSwitchCase="iconType.X" [ngClass]="iconClass"></digi-icon-x>
|
||||
<digi-icon-arrow-left *ngSwitchCase="iconType.ARROW_LEFT" [ngClass]="iconClass"></digi-icon-arrow-left>
|
||||
<digi-icon-arrow-right *ngSwitchCase="iconType.ARROW_RIGHT" [ngClass]="iconClass"></digi-icon-arrow-right>
|
||||
<digi-icon-eye *ngSwitchCase="iconType.EYE" [ngClass]="iconClass"></digi-icon-eye>
|
||||
<digi-icon-eye-slash *ngSwitchCase="iconType.EYESLASH" [ngClass]="iconClass"></digi-icon-eye-slash>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
@@ -0,0 +1,23 @@
|
||||
@import 'mixins/icon';
|
||||
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
&--s {
|
||||
@include msfa__digi-ng-icon(0.875em);
|
||||
}
|
||||
&--m {
|
||||
@include msfa__digi-ng-icon(1em);
|
||||
}
|
||||
&--l {
|
||||
@include msfa__digi-ng-icon(1.25em);
|
||||
}
|
||||
&--xl {
|
||||
@include msfa__digi-ng-icon(1.5em);
|
||||
}
|
||||
&--xxl {
|
||||
@include msfa__digi-ng-icon(2em);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* tslint:disable:no-unused-variable */
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { IconComponent } from './icon.component';
|
||||
|
||||
describe('IconComponent', () => {
|
||||
let component: IconComponent;
|
||||
let fixture: ComponentFixture<IconComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [IconComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(IconComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
|
||||
import { IconSize } from '@msfa-enums/icon-size.enum';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
const CUSTOM_ICONS: IconType[] = [IconType.HOME, IconType.SETTINGS, IconType.PLUS, IconType.CLIPBOARD];
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-icon',
|
||||
templateUrl: './icon.component.html',
|
||||
styleUrls: ['./icon.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class IconComponent implements OnChanges {
|
||||
@Input() icon: IconType;
|
||||
@Input() size: IconSize = IconSize.M;
|
||||
|
||||
iconClass: string;
|
||||
iconType = IconType;
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.iconClass = `icon--${this.size}`;
|
||||
}
|
||||
|
||||
get isCustomIcon(): boolean {
|
||||
return CUSTOM_ICONS.includes(this.icon);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { IconComponent } from './icon.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [IconComponent],
|
||||
imports: [CommonModule],
|
||||
exports: [IconComponent],
|
||||
})
|
||||
export class IconModule {}
|
||||
@@ -0,0 +1,7 @@
|
||||
<footer class="footer">
|
||||
<div class="footer__logo-wrapper">
|
||||
<a class="footer__logo-link" href="/">
|
||||
<img class="footer__logo" src="/assets/logo/arbetsformedlingen-light.svg" alt="Arbetsförmedlingen" />
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,15 @@
|
||||
.footer {
|
||||
background-color: var(--digi--ui--color--background--profile);
|
||||
padding: var(--digi--layout--gutter);
|
||||
|
||||
&__logo-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
height: 2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
describe('FooterComponent', () => {
|
||||
let component: FooterComponent;
|
||||
let fixture: ComponentFixture<FooterComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [FooterComponent],
|
||||
imports: [RouterTestingModule, IconModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FooterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-footer',
|
||||
templateUrl: './footer.component.html',
|
||||
styleUrls: ['./footer.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FooterComponent {}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FooterComponent } from './footer.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [FooterComponent],
|
||||
imports: [CommonModule, RouterModule],
|
||||
exports: [FooterComponent],
|
||||
})
|
||||
export class FooterModule {}
|
||||
@@ -0,0 +1,7 @@
|
||||
@media print {
|
||||
.footer {
|
||||
border-bottom-width: 0;
|
||||
padding: var(--digi--layout--gutter) 0;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="navigation">
|
||||
<div class="navigation__logo-wrapper">
|
||||
<a [routerLink]="['/']" aria-label="Till startsidan för FA Mina sidor">
|
||||
<digi-logo af-system-name="Mina sidor för fristående aktörer" af-color="secondary"></digi-logo>
|
||||
</a>
|
||||
</div>
|
||||
<ul class="navigation__list msfa__hide-on-print">
|
||||
<li *ngIf="user" class="navigation__item">
|
||||
<div class="navigation__user">
|
||||
<msfa-icon [icon]="iconType.USER" size="l"></msfa-icon>
|
||||
<span class="navigation__text">{{ user.fullName }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="navigation__item">
|
||||
<a routerLink="/" class="navigation__link">
|
||||
<msfa-icon [icon]="iconType.BELL" size="l"></msfa-icon>
|
||||
<span class="navigation__text">Notiser</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,67 @@
|
||||
@import 'mixins/list';
|
||||
@import 'variables/breakpoints';
|
||||
@import 'variables/colors';
|
||||
@import 'variables/gutters';
|
||||
@import 'variables/navigation';
|
||||
|
||||
.navigation {
|
||||
background-color: var(--digi--ui--color--background--profile);
|
||||
border-bottom: 1px solid var(--digi--ui--color--background--off);
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 var(--digi--layout--gutter);
|
||||
height: $msfa__navigation-height;
|
||||
|
||||
@media (min-width: $digi--layout--breakpoint--m) {
|
||||
height: $msfa__navigation-height-large;
|
||||
}
|
||||
|
||||
&__logo-wrapper {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
height: $msfa__navigation-height / 2.5;
|
||||
vertical-align: middle;
|
||||
|
||||
@media (min-width: $digi--layout--breakpoint--m) {
|
||||
height: $msfa__navigation-height-large / 2.5;
|
||||
}
|
||||
}
|
||||
|
||||
&__list {
|
||||
@include msfa__reset-list;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: $digi--layout--gutter--l;
|
||||
color: var(--digi--typography--color--text--light);
|
||||
margin-right: var(--digi--layout--gutter);
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&__user,
|
||||
&__link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: var(--digi--layout--gutter--s) var(--digi--layout--gutter);
|
||||
}
|
||||
|
||||
&__link {
|
||||
text-decoration: none;
|
||||
color: var(--digi--typography--color--text--light);
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 0.75rem;
|
||||
margin-top: var(--digi--layout--gutter--s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { NavigationComponent } from './navigation.component';
|
||||
|
||||
describe('NavigationComponent', () => {
|
||||
let component: NavigationComponent;
|
||||
let fixture: ComponentFixture<NavigationComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [NavigationComponent],
|
||||
imports: [RouterTestingModule, IconModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(NavigationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
import { User } from '@msfa-models/user.model';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-navigation',
|
||||
templateUrl: './navigation.component.html',
|
||||
styleUrls: ['./navigation.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NavigationComponent {
|
||||
@Input() user: User;
|
||||
iconType = IconType;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { NavigationComponent } from './navigation.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [NavigationComponent],
|
||||
imports: [CommonModule, RouterModule, IconModule],
|
||||
exports: [NavigationComponent],
|
||||
})
|
||||
export class NavigationModule {}
|
||||
@@ -0,0 +1,7 @@
|
||||
@media print {
|
||||
.navigation {
|
||||
border-bottom-width: 0;
|
||||
padding: var(--digi--layout--gutter) 0;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<nav class="sidebar" aria-label="Sidofält">
|
||||
<ul class="sidebar__list">
|
||||
<li class="sidebar__item">
|
||||
<a
|
||||
[routerLink]="['/']"
|
||||
[routerLinkActive]="['sidebar__link--active']"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
class="sidebar__link"
|
||||
>
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.HOME" size="xl"></msfa-icon>
|
||||
Hem
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/avrop']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.CLIPBOARD" size="xl"></msfa-icon>
|
||||
Avrop
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/deltagare']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.SOK_KANDIDAT" size="xl"></msfa-icon>
|
||||
Mina deltagare
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/planera-aktiviteter']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.USERS" size="xxl"></msfa-icon>
|
||||
Planera aktiviteter
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/rapportera']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.EDIT" size="xl"></msfa-icon>
|
||||
Rapportera
|
||||
</a>
|
||||
</li>
|
||||
<li class="sidebar__item">
|
||||
<a [routerLink]="['/administration']" [routerLinkActive]="['sidebar__link--active']" class="sidebar__link">
|
||||
<msfa-icon class="sidebar__icon" [icon]="iconType.SETTINGS" size="xl"></msfa-icon>
|
||||
Administration
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -0,0 +1,53 @@
|
||||
@import 'variables/colors';
|
||||
@import 'variables/gutters';
|
||||
@import 'variables/navigation';
|
||||
@import 'mixins/list';
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: sticky;
|
||||
top: $msfa__navigation-height-large;
|
||||
|
||||
&__list {
|
||||
@include msfa__reset-list;
|
||||
}
|
||||
|
||||
&__link {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--digi--layout--gutter--xs);
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: $digi--layout--gutter--m var(--digi--layout--gutter);
|
||||
border-bottom: 1px solid var(--digi--ui--color--background--off);
|
||||
color: var(--digi--typography--color--text) !important;
|
||||
text-decoration: none;
|
||||
font-weight: var(--digi--typography--font-weight);
|
||||
font-size: var(--digi--typography--font-size--s);
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--digi--ui--color--background--tertiary);
|
||||
}
|
||||
|
||||
&--active {
|
||||
background-color: var(--digi--ui--color--background--tertiary);
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 5px;
|
||||
background-color: var(--digi--ui--color--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
color: var(--digi--typography--color--link);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { SidebarComponent } from './sidebar.component';
|
||||
|
||||
describe('SidebarComponent', () => {
|
||||
let component: SidebarComponent;
|
||||
let fixture: ComponentFixture<SidebarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [SidebarComponent],
|
||||
imports: [RouterTestingModule, IconModule],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SidebarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { IconType } from '@msfa-enums/icon-type.enum';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-sidebar',
|
||||
templateUrl: './sidebar.component.html',
|
||||
styleUrls: ['./sidebar.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SidebarComponent {
|
||||
iconType = IconType;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { IconModule } from '@msfa-shared/components/icon/icon.module';
|
||||
import { SidebarComponent } from './sidebar.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SidebarComponent],
|
||||
imports: [CommonModule, RouterModule, IconModule],
|
||||
exports: [SidebarComponent],
|
||||
})
|
||||
export class SidebarModule {}
|
||||
@@ -0,0 +1 @@
|
||||
<a [attr.href]="skipLinkPath" class="skip-to-content">Gå till sidans innehåll</a>
|
||||
@@ -0,0 +1,29 @@
|
||||
@import 'variables/colors';
|
||||
|
||||
.skip-to-content {
|
||||
position: absolute;
|
||||
top: -1000px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 0;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
z-index: 1000;
|
||||
text-align: center;
|
||||
padding: var(--digi--layout--gutter--xs) var(--digi--layout--gutter);
|
||||
display: block;
|
||||
background-color: var(--digi--ui--color--complementary-alt);
|
||||
color: var(--digi--typography--color--text--light);
|
||||
|
||||
&:focus {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { SkipToContentComponent } from './skip-to-content.component';
|
||||
|
||||
describe('SkipToContentComponent', () => {
|
||||
let component: SkipToContentComponent;
|
||||
let fixture: ComponentFixture<SkipToContentComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [SkipToContentComponent],
|
||||
imports: [RouterTestingModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SkipToContentComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-skip-to-content',
|
||||
templateUrl: './skip-to-content.component.html',
|
||||
styleUrls: ['./skip-to-content.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SkipToContentComponent extends UnsubscribeDirective {
|
||||
@Input() mainContentId: string;
|
||||
skipLinkPath: string;
|
||||
|
||||
constructor(private router: Router, private changeDetectorRef: ChangeDetectorRef) {
|
||||
super();
|
||||
super.unsubscribeOnDestroy(
|
||||
this.router.events.pipe(filter((event: NavigationEnd) => event instanceof NavigationEnd)).subscribe(({ url }) => {
|
||||
const mainContentId = `#${this.mainContentId}`;
|
||||
// Check if the current URL already includes the mainContentId.
|
||||
const existsInUrl: boolean = url.substring(url.length - mainContentId.length, url.length) === mainContentId;
|
||||
|
||||
this.skipLinkPath = existsInUrl ? url : `${url}${mainContentId}`;
|
||||
this.changeDetectorRef.markForCheck();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SkipToContentComponent } from './skip-to-content.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SkipToContentComponent],
|
||||
imports: [CommonModule],
|
||||
exports: [SkipToContentComponent],
|
||||
})
|
||||
export class SkipToContentModule {}
|
||||
@@ -0,0 +1,19 @@
|
||||
<div class="msfa" *ngIf="isLoggedIn$ | async">
|
||||
<msfa-skip-to-content mainContentId="msfa-main-content"></msfa-skip-to-content>
|
||||
|
||||
<header class="msfa__header">
|
||||
<msfa-navigation [user]="user$ | async"></msfa-navigation>
|
||||
</header>
|
||||
|
||||
<msfa-sidebar class="msfa__sidebar"></msfa-sidebar>
|
||||
<main id="msfa-main-content" class="msfa__content">
|
||||
<digi-ng-navigation-breadcrumbs
|
||||
class="msfa__breadcrumbs"
|
||||
[afItems]="breadcrumbsItems"
|
||||
></digi-ng-navigation-breadcrumbs>
|
||||
|
||||
<ng-content></ng-content>
|
||||
</main>
|
||||
|
||||
<msfa-footer class="msfa__footer"></msfa-footer>
|
||||
</div>
|
||||
@@ -0,0 +1,48 @@
|
||||
@import 'variables/navigation';
|
||||
@import 'variables/breakpoints';
|
||||
@import 'variables/gutters';
|
||||
|
||||
.msfa {
|
||||
display: grid;
|
||||
height: 100vh;
|
||||
grid-template-columns: 12rem 1fr;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
grid-template-areas:
|
||||
'header header'
|
||||
'sidebar content'
|
||||
'footer footer';
|
||||
|
||||
// @media (min-width: $digi--layout--breakpoint--m) {
|
||||
// grid-template-rows: $msfa__navigation-height-large 1fr auto;
|
||||
// }
|
||||
|
||||
&__header {
|
||||
grid-area: header;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
&__sidebar {
|
||||
grid-area: sidebar;
|
||||
background-color: var(--digi--ui--color--background--secondary);
|
||||
border-right: 1px solid var(--digi--ui--color--background--off);
|
||||
}
|
||||
|
||||
&__content {
|
||||
grid-area: content;
|
||||
max-width: $digi--layout--breakpoint--l;
|
||||
padding: var(--digi--layout--gutter) $digi--layout--gutter--l $digi--layout--gutter--xxl;
|
||||
}
|
||||
|
||||
&__breadcrumbs {
|
||||
display: block;
|
||||
margin-bottom: var(--digi--layout--gutter);
|
||||
}
|
||||
|
||||
&__footer {
|
||||
grid-area: footer;
|
||||
background-color: var(--digi--ui--color--primary);
|
||||
min-height: 10rem;
|
||||
}
|
||||
}
|
||||
@@ -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 { LayoutComponent } from './Layout.component';
|
||||
|
||||
describe('LayoutComponent', () => {
|
||||
let component: LayoutComponent;
|
||||
let fixture: ComponentFixture<LayoutComponent>;
|
||||
|
||||
beforeEach(
|
||||
waitForAsync(() => {
|
||||
void TestBed.configureTestingModule({
|
||||
declarations: [LayoutComponent],
|
||||
imports: [RouterTestingModule, HttpClientTestingModule],
|
||||
}).compileComponents();
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LayoutComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { NavigationBreadcrumbsItem } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { UnsubscribeDirective } from '@msfa-directives/unsubscribe.directive';
|
||||
import { User } from '@msfa-models/user.model';
|
||||
import { AuthenticationService } from '@msfa-services/api/authentication.service';
|
||||
import { UserService } from '@msfa-services/api/user.service';
|
||||
import { mapPathsToBreadcrumbs } from '@msfa-utils/map-paths-to-breadcrumbs.util';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { filter, switchMap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'msfa-layout',
|
||||
templateUrl: './layout.component.html',
|
||||
styleUrls: ['./layout.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class LayoutComponent extends UnsubscribeDirective {
|
||||
private startBreadcrumb: NavigationBreadcrumbsItem = {
|
||||
text: 'Start',
|
||||
routerLink: '/',
|
||||
};
|
||||
private _breadcrumbsItems$ = new BehaviorSubject<NavigationBreadcrumbsItem[]>([this.startBreadcrumb]);
|
||||
isLoggedIn$: Observable<boolean> = this.authService.isLoggedIn$;
|
||||
user$: Observable<User> = this.isLoggedIn$.pipe(
|
||||
filter(loggedIn => !!loggedIn),
|
||||
switchMap(() => this.userService.user$)
|
||||
);
|
||||
|
||||
get breadcrumbsItems(): NavigationBreadcrumbsItem[] {
|
||||
return this._breadcrumbsItems$.getValue();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private authService: AuthenticationService,
|
||||
private userService: UserService
|
||||
) {
|
||||
super();
|
||||
super.unsubscribeOnDestroy(
|
||||
this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => {
|
||||
const urlTree = this.router.parseUrl(this.router.url);
|
||||
if (urlTree.queryParams.code) {
|
||||
void this.router.navigate([], {
|
||||
relativeTo: this.activatedRoute,
|
||||
queryParams: { code: null },
|
||||
queryParamsHandling: 'merge',
|
||||
replaceUrl: true,
|
||||
});
|
||||
}
|
||||
urlTree.queryParams = {};
|
||||
const paths = urlTree
|
||||
.toString()
|
||||
.split('/')
|
||||
.filter(path => !!path);
|
||||
this._breadcrumbsItems$.next(mapPathsToBreadcrumbs(paths, this.startBreadcrumb));
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { DigiNgNavigationBreadcrumbsModule } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
import { FooterModule } from './components/footer/footer.module';
|
||||
import { NavigationModule } from './components/navigation/navigation.module';
|
||||
import { SidebarModule } from './components/sidebar/sidebar.module';
|
||||
import { SkipToContentModule } from './components/skip-to-content/skip-to-content.module';
|
||||
import { LayoutComponent } from './layout.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LayoutComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
SkipToContentModule,
|
||||
NavigationModule,
|
||||
SidebarModule,
|
||||
FooterModule,
|
||||
MarkdownModule.forRoot({ loader: HttpClient }),
|
||||
DigiNgNavigationBreadcrumbsModule,
|
||||
],
|
||||
exports: [LayoutComponent],
|
||||
})
|
||||
export class LayoutModule {}
|
||||
@@ -0,0 +1,17 @@
|
||||
export const DRIVERS_LICENSES = [
|
||||
'AM',
|
||||
'A1',
|
||||
'A2',
|
||||
'A',
|
||||
'B',
|
||||
'BE',
|
||||
'B96',
|
||||
'C1',
|
||||
'C',
|
||||
'C1E',
|
||||
'CE',
|
||||
'D1',
|
||||
'D',
|
||||
'D1E',
|
||||
'DE',
|
||||
];
|
||||
10
apps/mina-sidor-fa/src/app/shared/constants/navigation.ts
Normal file
10
apps/mina-sidor-fa/src/app/shared/constants/navigation.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export const NAVIGATION = {
|
||||
administration: 'Administration',
|
||||
'skapa-konto': 'Skapa nytt konto',
|
||||
personal: 'Hantera personal',
|
||||
deltagare: 'Deltagare',
|
||||
avrop: 'Avrop',
|
||||
meddelanden: 'Meddelanden',
|
||||
statistik: 'Statistik',
|
||||
installningar: 'Inställningar',
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Directive, OnDestroy } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Directive()
|
||||
export class UnsubscribeDirective implements OnDestroy {
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.subscriptions.forEach(sub => sub.unsubscribe());
|
||||
}
|
||||
|
||||
unsubscribeOnDestroy(...sub: Subscription[]): void {
|
||||
this.subscriptions.push(...sub);
|
||||
}
|
||||
}
|
||||
16
apps/mina-sidor-fa/src/app/shared/enums/address-type.enum.ts
Normal file
16
apps/mina-sidor-fa/src/app/shared/enums/address-type.enum.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum Authorization {
|
||||
UserManagement = 'UserManagement',
|
||||
Economy = 'Economy',
|
||||
Reports = 'Reports',
|
||||
ParticipantManagement = 'ParticipantManagement',
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export enum ErrorSeverity {
|
||||
HIGH = 'High',
|
||||
MEDIUM = 'Medium',
|
||||
LOW = 'Low'
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export enum ErrorType {
|
||||
API = 'API Error',
|
||||
NETWORK = 'Network Error',
|
||||
APP = 'Application Error',
|
||||
UNKNOWN = 'Unknown Error'
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export enum IconSize {
|
||||
S = 's',
|
||||
M = 'm',
|
||||
L = 'l',
|
||||
XL = 'xl',
|
||||
XXL = 'xxl',
|
||||
}
|
||||
21
apps/mina-sidor-fa/src/app/shared/enums/icon-type.enum.ts
Normal file
21
apps/mina-sidor-fa/src/app/shared/enums/icon-type.enum.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export enum IconType {
|
||||
HOME = 'home', // Custom
|
||||
SETTINGS = 'settings', // Custom
|
||||
PLUS = 'plus', // Custom
|
||||
CLIPBOARD = 'clipboard', // Custom
|
||||
USER = 'user',
|
||||
USERS = 'users',
|
||||
BELL = 'bell',
|
||||
CALENDAR = 'calendar',
|
||||
ENVELOPE = 'envelope',
|
||||
SOK_KANDIDAT = 'sok-kandidat',
|
||||
EDIT = 'edit',
|
||||
INFO = 'info',
|
||||
WARNING = 'warning',
|
||||
APPROVED = 'approved',
|
||||
X = 'x',
|
||||
ARROW_LEFT = 'arrow-left',
|
||||
ARROW_RIGHT = 'arrow-right',
|
||||
EYE = 'eye',
|
||||
EYESLASH = 'eyeslash',
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum KeyboardCodes {
|
||||
ENTER = 'Enter',
|
||||
ESCAPE = 'Escape',
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum ParticipantStatus {
|
||||
ACTIVE = 'active',
|
||||
FOLLOW_UP = 'follow-up',
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
5
apps/mina-sidor-fa/src/app/shared/enums/service.enum.ts
Normal file
5
apps/mina-sidor-fa/src/app/shared/enums/service.enum.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export enum Service {
|
||||
KVL = 'KVL',
|
||||
KROM = 'KROM',
|
||||
STOM = 'STOM',
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export enum SortOrder {
|
||||
ASC = 'asc',
|
||||
DESC = 'desc',
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export enum ToastPosition {
|
||||
TOP_RIGHT = 'top-right',
|
||||
TOP_CENTER = 'top-center',
|
||||
TOP_LEFT = 'top-left',
|
||||
BOTTOM_RIGHT = 'bottom-right',
|
||||
BOTTOM_CENTER = 'bottom-center',
|
||||
BOTTOM_LEFT = 'bottom-left',
|
||||
CENTER_RIGHT = 'center-right',
|
||||
CENTER_CENTER = 'center-center',
|
||||
CENTER_LEFT = 'center-left',
|
||||
}
|
||||
30
apps/mina-sidor-fa/src/app/shared/guards/auth.guard.ts
Normal file
30
apps/mina-sidor-fa/src/app/shared/guards/auth.guard.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
||||
import { environment } from '@msfa-environment';
|
||||
import { AuthenticationService } from '@msfa-services/api/authentication.service';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private authenticationService: AuthenticationService, private router: Router) {}
|
||||
|
||||
canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
|
||||
return this.authenticationService.isLoggedIn$.pipe(
|
||||
switchMap(loggedIn => {
|
||||
if (loggedIn) {
|
||||
return of(true);
|
||||
} else if (route.queryParams.code) {
|
||||
return this.authenticationService.login$(route.queryParams.code).pipe(map(result => !!result));
|
||||
}
|
||||
|
||||
if (environment.environment === 'local') {
|
||||
void this.router.navigateByUrl(environment.loginUrl);
|
||||
} else {
|
||||
document.location.href = `${environment.loginUrl}&client_id=${environment.clientId}&redirect_uri=${window.location.origin}`;
|
||||
}
|
||||
return of(false);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ErrorHandler, Injectable } from '@angular/core';
|
||||
import { CustomError, errorToCustomError } from '@msfa-models/error/custom-error';
|
||||
import { ErrorService } from '@msfa-services/error.service';
|
||||
|
||||
@Injectable()
|
||||
export class CustomErrorHandler implements ErrorHandler {
|
||||
constructor(private errorService: ErrorService) {}
|
||||
|
||||
handleError(error: Error & { ngDebugContext: unknown }): void {
|
||||
const customError: CustomError = errorToCustomError(error);
|
||||
console.error(error);
|
||||
this.errorService.add(customError);
|
||||
}
|
||||
}
|
||||
20
apps/mina-sidor-fa/src/app/shared/models/address.model.ts
Normal file
20
apps/mina-sidor-fa/src/app/shared/models/address.model.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { AddressType, getAddressType } from '@msfa-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,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface AddressResponse {
|
||||
adresstyp: 'FBF' | 'EgenAngiven';
|
||||
gatuadress: string;
|
||||
postnummer: string;
|
||||
postort: string;
|
||||
land: string;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export interface AuthenticationResponse {
|
||||
id: string;
|
||||
access_token: string;
|
||||
scope: string;
|
||||
id_token: string;
|
||||
token_type: string;
|
||||
expires_in: number;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
export interface AvropResponse {
|
||||
id: string;
|
||||
deltagare: string;
|
||||
genomforandeReferens: number;
|
||||
orgId: string;
|
||||
leverantorId: number;
|
||||
organisationsnummer: string;
|
||||
utforandeVerksamhetId: number;
|
||||
utforandeverksamhet: string;
|
||||
kommunKod: string;
|
||||
kommun: string;
|
||||
utforandeAdressId: number;
|
||||
adress: string;
|
||||
ordernummer: string;
|
||||
bokningsId: number;
|
||||
personnummer: string;
|
||||
sokandeId: number;
|
||||
tjanstekod: string;
|
||||
tjansteNamn: string;
|
||||
deltagandeGrad: number;
|
||||
startdatumAvrop: string;
|
||||
slutdatumAvrop: string;
|
||||
aktnummerDiariet: string;
|
||||
tolkbehov: string;
|
||||
sprakstod: string;
|
||||
sparkod: string;
|
||||
sparNamn: string;
|
||||
supervisorId: number;
|
||||
recievedTimestamp: string;
|
||||
}
|
||||
@@ -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[];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { AvropResponse } from './avrop.response.model';
|
||||
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 { WorkExperiencesResponse } from './work-experiences.response.model';
|
||||
import { WorkLanguagesResponse } from './work-languages.response.model';
|
||||
|
||||
export interface DeltagareCompactResponse {
|
||||
sokandeId: string;
|
||||
deltagare: string;
|
||||
kommun: string;
|
||||
}
|
||||
|
||||
export interface DeltagareResponse {
|
||||
id: string;
|
||||
contact: ContactInformationResponse;
|
||||
driverlicense: DriversLicenseResponse;
|
||||
highestEducation: HighestEducationResponse;
|
||||
educations: EducationsResponse;
|
||||
translator: TranslatorResponse;
|
||||
workLanguages: WorkLanguagesResponse;
|
||||
disabilities: DisabilitiesResponse;
|
||||
workExperiences: WorkExperiencesResponse;
|
||||
avropInformation: AvropResponse;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { DisabilityResponse } from './disability.response.model';
|
||||
|
||||
export interface DisabilitiesResponse {
|
||||
funktionsnedsattningar: DisabilityResponse[];
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface DisabilityResponse {
|
||||
|
||||
kod: string;
|
||||
funktionsnedsattning: string;
|
||||
beskrivning: string;
|
||||
utgatt: boolean;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface DriversLicenseResponse {
|
||||
korkort: { behorighet: string };
|
||||
tillgang_till_bil: boolean;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface EducationLevelResponse {
|
||||
utbildningsniva: string;
|
||||
beskrivning: string;
|
||||
taxonomy_id: number;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface EducationResponse {
|
||||
utbildning: string;
|
||||
beskrivning: string;
|
||||
anordnare: string;
|
||||
period_from: string;
|
||||
period_tom: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { EducationResponse } from './education.response.model';
|
||||
|
||||
export interface EducationsResponse {
|
||||
utbildningar: EducationResponse[];
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface EmployeeInviteMockApiResponse {
|
||||
id: number,
|
||||
createdAt: number
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface HandledareResponse {
|
||||
id: number;
|
||||
name: string
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface HighestEducationResponse {
|
||||
utbildningsniva: string;
|
||||
beskrivning_utbildningsniva: string;
|
||||
sun_kod: string;
|
||||
beskrivning_sun_kod: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface KommunResponse {
|
||||
kommunCode: number;
|
||||
kommun: string;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface LanguageResponse {
|
||||
beskrivning: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface OrganizationResponse {
|
||||
name: string;
|
||||
organizationnumber: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface PhoneNumberResponse {
|
||||
landskod: number;
|
||||
nummer_utan_inledande_nolla: number;
|
||||
telekomtyp: 'Mobil' | 'Bostad';
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface SunKodResponse {
|
||||
sun_kod: string;
|
||||
beskrivning: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface TjanstResponse {
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { LanguageResponse } from './language.response.model';
|
||||
|
||||
export interface TranslatorResponse {
|
||||
sprak: LanguageResponse;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface UserInfoResponse {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
roles: string[];
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export interface UtforandeVerksamhetResponse {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
export interface WorkExperienceResponse {
|
||||
yrke: string;
|
||||
beskrivning: string;
|
||||
arbetsgivare: string;
|
||||
period_from: string;
|
||||
period_tom: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { WorkExperienceResponse } from './work-experience.response.model';
|
||||
|
||||
export interface WorkExperiencesResponse {
|
||||
arbetslivserfarenheter: WorkExperienceResponse[];
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { LanguageResponse } from './language.response.model';
|
||||
|
||||
export interface WorkLanguagesResponse {
|
||||
sprak: LanguageResponse[];
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AuthenticationResponse } from './api/authentication.response.model';
|
||||
|
||||
export interface Authentication {
|
||||
idToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
|
||||
export function mapAuthApiResponseToAuthenticationResult(data: AuthenticationResponse): Authentication {
|
||||
const { id_token, expires_in } = data;
|
||||
return {
|
||||
idToken: id_token,
|
||||
expiresIn: expires_in,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Authorization as AuthorizationEnum } from '@msfa-enums/authorization.enum';
|
||||
|
||||
export interface Authorization {
|
||||
id: string;
|
||||
name: AuthorizationEnum;
|
||||
}
|
||||
|
||||
export interface AuthorizationApiResponse {
|
||||
data: AuthorizationApiResponseData[];
|
||||
}
|
||||
|
||||
export interface AuthorizationApiResponseData {
|
||||
id: string;
|
||||
name: AuthorizationEnum;
|
||||
}
|
||||
|
||||
export function mapAuthorizationApiResponseToAuthorization(data: AuthorizationApiResponseData): Authorization {
|
||||
const { id, name } = data;
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
};
|
||||
}
|
||||
57
apps/mina-sidor-fa/src/app/shared/models/avrop.model.ts
Normal file
57
apps/mina-sidor-fa/src/app/shared/models/avrop.model.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { AvropResponse } from './api/avrop.response.model';
|
||||
|
||||
export interface AvropCompact {
|
||||
id: string; // id
|
||||
sokandeId: number; // sokandeId
|
||||
fullName: string; // deltagare
|
||||
tjanst: string; // tjansteNamn
|
||||
startDate: Date; // startdatumAvrop
|
||||
endDate: Date; // slutdatumAvrop
|
||||
tolkbehov: string; // tolkbehov
|
||||
sprakstod: string; // sprakstod
|
||||
utforandeAdress: string; // adress
|
||||
trackCode: string; // sparkod
|
||||
trackName: string; // sparNamn
|
||||
}
|
||||
|
||||
export interface Avrop extends AvropCompact {
|
||||
genomforandeReferens: number; // genomforandeReferens
|
||||
participationFrequency: number; // deltagandeGrad
|
||||
utforandeVerksamhet: string; // utforandeverksamhet
|
||||
}
|
||||
|
||||
export function mapAvropResponseToAvrop(data: AvropResponse): Avrop {
|
||||
const {
|
||||
id,
|
||||
sokandeId,
|
||||
deltagare,
|
||||
tjansteNamn,
|
||||
startdatumAvrop,
|
||||
slutdatumAvrop,
|
||||
tolkbehov,
|
||||
sprakstod,
|
||||
adress,
|
||||
sparkod,
|
||||
sparNamn,
|
||||
genomforandeReferens,
|
||||
deltagandeGrad,
|
||||
utforandeverksamhet,
|
||||
} = data;
|
||||
|
||||
return {
|
||||
id,
|
||||
sokandeId,
|
||||
fullName: deltagare,
|
||||
tjanst: tjansteNamn,
|
||||
startDate: new Date(startdatumAvrop),
|
||||
endDate: new Date(slutdatumAvrop),
|
||||
tolkbehov: tolkbehov,
|
||||
sprakstod: sprakstod,
|
||||
utforandeAdress: adress,
|
||||
trackCode: sparkod,
|
||||
trackName: sparNamn,
|
||||
genomforandeReferens,
|
||||
participationFrequency: deltagandeGrad,
|
||||
utforandeVerksamhet: utforandeverksamhet,
|
||||
};
|
||||
}
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface DateFormatOptions {
|
||||
year?: 'short' | 'long' | 'numeric';
|
||||
month?: 'short' | 'long' | 'numeric';
|
||||
day?: 'short' | 'long' | 'numeric';
|
||||
weekday?: 'short' | 'long' | 'numeric';
|
||||
}
|
||||
78
apps/mina-sidor-fa/src/app/shared/models/deltagare.model.ts
Normal file
78
apps/mina-sidor-fa/src/app/shared/models/deltagare.model.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { Address } from './address.model';
|
||||
import { AvropResponse } from './api/avrop.response.model';
|
||||
import { DeltagareResponse } from './api/deltagare.response.model';
|
||||
import { Avrop, mapAvropResponseToAvrop } from './avrop.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';
|
||||
import { mapResponseToWorkExperience, WorkExperience } from './work-experience.model';
|
||||
|
||||
export interface DeltagareCompact {
|
||||
id: string;
|
||||
fullName: string;
|
||||
utforandeVerksamhet: string;
|
||||
utforandeAdress: string;
|
||||
}
|
||||
|
||||
export interface Deltagare {
|
||||
id: string;
|
||||
fullName: string;
|
||||
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[];
|
||||
avropInformation: Avrop;
|
||||
}
|
||||
|
||||
export function mapResponseToDeltagareCompact(data: AvropResponse): DeltagareCompact {
|
||||
const { sokandeId, deltagare, adress, utforandeverksamhet } = data;
|
||||
return {
|
||||
id: sokandeId.toString(),
|
||||
fullName: deltagare,
|
||||
utforandeVerksamhet: utforandeverksamhet,
|
||||
utforandeAdress: adress,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapResponseToDeltagare(data: DeltagareResponse): Deltagare {
|
||||
const {
|
||||
id,
|
||||
contact,
|
||||
driverlicense,
|
||||
highestEducation,
|
||||
educations,
|
||||
translator,
|
||||
workLanguages,
|
||||
disabilities,
|
||||
workExperiences,
|
||||
avropInformation,
|
||||
} = 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)),
|
||||
workExperiences:
|
||||
workExperiences &&
|
||||
workExperiences.arbetslivserfarenheter.map(workExperience => mapResponseToWorkExperience(workExperience)),
|
||||
avropInformation: avropInformation && mapAvropResponseToAvrop(avropInformation),
|
||||
};
|
||||
}
|
||||
16
apps/mina-sidor-fa/src/app/shared/models/disability.model.ts
Normal file
16
apps/mina-sidor-fa/src/app/shared/models/disability.model.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
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,
|
||||
description: beskrivning,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { DRIVERS_LICENSES } from '@msfa-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,
|
||||
};
|
||||
}
|
||||
22
apps/mina-sidor-fa/src/app/shared/models/education.model.ts
Normal file
22
apps/mina-sidor-fa/src/app/shared/models/education.model.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { formatToDate } from '@msfa-utils/format-to-date.util';
|
||||
import { EducationResponse } from './api/education.response.model';
|
||||
|
||||
export interface Education {
|
||||
education: string;
|
||||
description: string;
|
||||
organizer: string;
|
||||
dateFrom: Date;
|
||||
dateTo: Date;
|
||||
}
|
||||
|
||||
export function mapResponseToEducation(data: EducationResponse): Education {
|
||||
const { utbildning, beskrivning, anordnare, period_from, period_tom } = data;
|
||||
|
||||
return {
|
||||
education: utbildning,
|
||||
description: beskrivning,
|
||||
organizer: anordnare,
|
||||
dateFrom: formatToDate(period_from),
|
||||
dateTo: formatToDate(period_tom),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface EmployeeInviteMockaData {
|
||||
id: number
|
||||
}
|
||||
75
apps/mina-sidor-fa/src/app/shared/models/employee.model.ts
Normal file
75
apps/mina-sidor-fa/src/app/shared/models/employee.model.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { Authorization } from '@msfa-enums/authorization.enum';
|
||||
import { Organization } from './organization.model';
|
||||
import { PaginationMeta } from './pagination-meta.model';
|
||||
import { Service } from './service.model';
|
||||
|
||||
export interface Employee {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
fullName?: string;
|
||||
ssn: string;
|
||||
organizations: Organization[];
|
||||
services: Service[];
|
||||
authorizations: Authorization[];
|
||||
createdAt?: number;
|
||||
}
|
||||
|
||||
export interface EmployeesApiResponse {
|
||||
data: Employee[];
|
||||
meta: PaginationMeta;
|
||||
}
|
||||
|
||||
export interface EmployeesData {
|
||||
data: Employee[];
|
||||
meta: PaginationMeta;
|
||||
}
|
||||
|
||||
export interface EmployeeApiResponse {
|
||||
data: Employee;
|
||||
}
|
||||
|
||||
export interface EmployeeApiResponseData {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
ssn: string;
|
||||
organizations: Organization[];
|
||||
authorizations: Authorization[];
|
||||
services: Service[];
|
||||
}
|
||||
|
||||
export interface EmployeeApiRequestData {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
ssn: string;
|
||||
organizations: Organization[];
|
||||
services: Service[];
|
||||
authorizations: Authorization[];
|
||||
}
|
||||
|
||||
export function mapEmployeeToEmployeeApiRequestData(data: Employee): EmployeeApiRequestData {
|
||||
const { firstName, lastName, ssn, services, organizations, authorizations } = data;
|
||||
return {
|
||||
firstName,
|
||||
lastName,
|
||||
ssn,
|
||||
services,
|
||||
organizations,
|
||||
authorizations,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapEmployeeReponseToEmployee(data: EmployeeApiResponseData): Employee {
|
||||
const { id, firstName, lastName, ssn, services, organizations, authorizations } = data;
|
||||
return {
|
||||
id,
|
||||
firstName,
|
||||
lastName,
|
||||
fullName: `${firstName} ${lastName}`,
|
||||
organizations,
|
||||
authorizations,
|
||||
services,
|
||||
ssn,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export interface Environment {
|
||||
environment: 'api' | 'local' | 'prod';
|
||||
clientId: string;
|
||||
loginUrl: string;
|
||||
production: boolean;
|
||||
api: {
|
||||
url: string;
|
||||
headers: { [key: string]: string };
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { ErrorSeverity } from '@msfa-enums/error-severity.enum';
|
||||
import { ErrorType } from '@msfa-enums/error-type.enum';
|
||||
|
||||
export class CustomError implements Error {
|
||||
id: string;
|
||||
name: string;
|
||||
message: string;
|
||||
stack: string;
|
||||
type: ErrorType;
|
||||
severity: ErrorSeverity;
|
||||
timestamp: Date;
|
||||
error: Error;
|
||||
removeAfter: number;
|
||||
|
||||
constructor(args: { error: Error; type?: ErrorType; message?: string; severity?: ErrorSeverity; stack?: string }) {
|
||||
this.timestamp = new Date();
|
||||
this.id = this.timestamp.getTime().toString();
|
||||
this.type = this.name = args.type || ErrorType.UNKNOWN;
|
||||
this.message = args.message || args.error.message;
|
||||
this.severity = args.severity || ErrorSeverity.HIGH;
|
||||
this.stack = args.stack || CustomError.getStack(args.error);
|
||||
this.error = args.error;
|
||||
this.removeAfter =
|
||||
this.severity === ErrorSeverity.LOW ? 5000 : this.severity === ErrorSeverity.MEDIUM ? 10000 : 20000;
|
||||
}
|
||||
|
||||
static getStack(error: Error | { error: Error }): string {
|
||||
if (!error) {
|
||||
return '';
|
||||
}
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
if ('stack' in error) {
|
||||
return error.stack;
|
||||
} else if ('error' in error) {
|
||||
return this.getStack(error.error);
|
||||
} else {
|
||||
return error as never;
|
||||
}
|
||||
}
|
||||
|
||||
static getErrorType(error: Error | (Error & { type: ErrorType })): ErrorType {
|
||||
if (typeof error === 'object' && 'type' in error) {
|
||||
return error.type;
|
||||
} else if (error.name === 'HttpErrorResponse') {
|
||||
return ErrorType.API;
|
||||
}
|
||||
|
||||
return ErrorType.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
export function errorToCustomError(error: Error & { ngDebugContext: unknown }): CustomError {
|
||||
const type = CustomError.getErrorType(error);
|
||||
const message = error.message || error;
|
||||
const severity = ErrorSeverity.HIGH;
|
||||
|
||||
// this is done to avoid circular references while running in debug mode
|
||||
if ('ngDebugContext' in error) {
|
||||
error.ngDebugContext = {};
|
||||
}
|
||||
|
||||
return new CustomError({
|
||||
error,
|
||||
type,
|
||||
severity,
|
||||
message: message as string,
|
||||
});
|
||||
}
|
||||
17
apps/mina-sidor-fa/src/app/shared/models/handledare.model.ts
Normal file
17
apps/mina-sidor-fa/src/app/shared/models/handledare.model.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { HandledareResponse } from './api/handledare.response.model';
|
||||
|
||||
export interface Handledare {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export function mapHandledareResponseToHandledare(
|
||||
data: HandledareResponse
|
||||
): Handledare {
|
||||
const { id, name } = data;
|
||||
|
||||
return {
|
||||
id,
|
||||
name
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user