feat(login): Added auth-guard to avoid unauthorized access
Squashed commit of the following:
commit c8f20f6ff0dee2257a4191d8e6771ed2fc364326
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Wed Jun 30 12:04:40 2021 +0200
Removed current from currentUser and currentToken/currentExpiration
commit fef6b046861efe8cfacb5b5b1e9dbb86bff42336
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Wed Jun 30 10:42:27 2021 +0200
Fixed some tests
commit f357546d3a61ad66d804a7cb36807985c8435974
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Wed Jun 30 09:41:47 2021 +0200
Fixed linting
commit 85fdbaed8d922bec235e4987cc34464c1419a093
Merge: c93dd92 c06452d
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Wed Jun 30 09:29:55 2021 +0200
Merged develop and resolved conflicts
commit c93dd925b06a0b8a0361a687165e9c3954e2050b
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Wed Jun 30 07:43:57 2021 +0200
Moved some components to shared folder
commit aa1cc2b6240236149b0367363d4175fbdacf94dc
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Wed Jun 30 07:32:28 2021 +0200
Removed comments and some unused code
commit 7b83eb9d9d368b7466189ab3588fa91697db49c0
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Tue Jun 29 14:56:02 2021 +0200
Login-flow now works locally and against API
commit dab5a76f2b6e24447d85e237233053a3f23b1b39
Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se>
Date: Tue Jun 29 12:50:24 2021 +0200
Adjusted login-functionality to use a guard
This commit is contained in:
@@ -1,56 +1,60 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ExtraOptions, RouterModule, Routes } from '@angular/router';
|
||||
import { environment } from '@dafa-environment';
|
||||
import { AuthGuard } from '@dafa-guards/auth.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
data: { title: '' },
|
||||
loadChildren: () => import('./pages/start/start.module').then(m => m.StartModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'administration',
|
||||
data: { title: 'Administration' },
|
||||
loadChildren: () => import('./pages/administration/administration.module').then(m => m.AdministrationModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'deltagare',
|
||||
data: { title: 'Deltagare' },
|
||||
loadChildren: () => import('./pages/participants/participants.module').then(m => m.ParticipantsModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'avrop',
|
||||
data: { title: 'Avrop' },
|
||||
loadChildren: () => import('./pages/avrop/avrop.module').then(m => m.AvropModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'meddelanden',
|
||||
data: { title: 'Meddelanden' },
|
||||
loadChildren: () => import('./pages/messages/messages.module').then(m => m.MessagesModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'statistik',
|
||||
data: { title: 'Statistik' },
|
||||
loadChildren: () => import('./pages/statistics/statistics.module').then(m => m.StatisticsModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'installningar',
|
||||
data: { title: 'Inställningar' },
|
||||
loadChildren: () => import('./pages/settings/settings.module').then(m => m.SettingsModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'releases',
|
||||
data: { title: 'Releases' },
|
||||
loadChildren: () => import('./pages/releases/releases.module').then(m => m.ReleasesModule),
|
||||
},
|
||||
{
|
||||
path: 'ciam-landing',
|
||||
data: { title: 'Ciam landing page' },
|
||||
loadChildren: () => import('./pages/ciam-landing/ciam-landing.module').then(m => m.CiamLandingModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
{
|
||||
path: 'logout',
|
||||
data: { title: 'Ciam landing page' },
|
||||
data: { title: 'Logga ut' },
|
||||
loadChildren: () => import('./pages/logout/logout.module').then(m => m.LogoutModule),
|
||||
},
|
||||
];
|
||||
@@ -67,6 +71,7 @@ routes.push({
|
||||
path: '**',
|
||||
data: { title: 'Sidan hittas inte' },
|
||||
loadChildren: () => import('./pages/page-not-found/page-not-found.module').then(m => m.PageNotFoundModule),
|
||||
canActivate: [AuthGuard],
|
||||
});
|
||||
|
||||
const options: ExtraOptions = {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
<dafa-toast-list></dafa-toast-list>
|
||||
|
||||
@@ -3,16 +3,13 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
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';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [AppComponent],
|
||||
imports: [RouterTestingModule, HttpClientTestingModule, SkipToContentModule, NavigationModule, SidebarModule],
|
||||
imports: [RouterTestingModule, HttpClientTestingModule],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
|
||||
@@ -6,6 +6,4 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
styleUrls: ['./app.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AppComponent {
|
||||
|
||||
}
|
||||
export class AppComponent {}
|
||||
|
||||
@@ -1,42 +1,24 @@
|
||||
import { DigiNgNavigationBreadcrumbsModule } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { ErrorHandler, NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AuthGuard } from '@dafa-guards/auth.guard';
|
||||
import { CustomErrorHandler } from '@dafa-interceptors/custom-error-handler.module';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
import { AuthInterceptor } from '@dafa-services/api/auth.interceptor';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
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 { ToastListModule } from './components/toast-list/toast-list.module';
|
||||
import { AuthInterceptor } from '@dafa-services/api/auth.interceptor';
|
||||
import { AvropModule } from './pages/avrop/avrop.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
RouterModule,
|
||||
SkipToContentModule,
|
||||
NavigationModule,
|
||||
SidebarModule,
|
||||
ToastListModule,
|
||||
FooterModule,
|
||||
MarkdownModule.forRoot({ loader: HttpClient }),
|
||||
DigiNgNavigationBreadcrumbsModule,
|
||||
AvropModule,
|
||||
],
|
||||
imports: [BrowserModule, HttpClientModule, AppRoutingModule, ToastListModule, AvropModule],
|
||||
providers: [
|
||||
{
|
||||
provide: ErrorHandler,
|
||||
useClass: CustomErrorHandler,
|
||||
},
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
|
||||
AuthGuard,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { LoggedInShellComponent } from './logged-in-shell.component';
|
||||
import { SkipToContentModule } from '../skip-to-content/skip-to-content.module';
|
||||
import { NavigationModule } from '../navigation/navigation.module';
|
||||
import { SidebarModule } from '../sidebar/sidebar.module';
|
||||
import { DigiNgNavigationBreadcrumbsModule } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { FooterModule } from '../footer/footer.module';
|
||||
import { ToastListModule } from '../toast-list/toast-list.module';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule,
|
||||
CommonModule,
|
||||
SkipToContentModule,
|
||||
NavigationModule,
|
||||
SidebarModule,
|
||||
DigiNgNavigationBreadcrumbsModule,
|
||||
FooterModule,
|
||||
ToastListModule,
|
||||
],
|
||||
declarations: [LoggedInShellComponent],
|
||||
exports: [LoggedInShellComponent],
|
||||
})
|
||||
export class LoggedInShellModule {}
|
||||
@@ -1,15 +1,9 @@
|
||||
|
||||
|
||||
export interface AuthenticationResult {
|
||||
idToken: string;
|
||||
expiresIn: number;
|
||||
}
|
||||
|
||||
export interface AuthenticationApiResponse {
|
||||
data: AuthenticationApiResponseData;
|
||||
}
|
||||
|
||||
export interface AuthenticationApiResponseData {
|
||||
id: string;
|
||||
access_token: string;
|
||||
scope: string;
|
||||
@@ -18,12 +12,10 @@ export interface AuthenticationApiResponseData {
|
||||
expires_in: number;
|
||||
}
|
||||
|
||||
export function mapAuthApiResponseToAuthenticationResult(data: AuthenticationApiResponseData): AuthenticationResult {
|
||||
const {
|
||||
id_token,
|
||||
expires_in } = data;
|
||||
export function mapAuthApiResponseToAuthenticationResult(data: AuthenticationApiResponse): AuthenticationResult {
|
||||
const { id_token, expires_in } = data;
|
||||
return {
|
||||
idToken: id_token,
|
||||
expiresIn: expires_in
|
||||
expiresIn: expires_in,
|
||||
};
|
||||
}
|
||||
|
||||
30
apps/dafa-web/src/app/guards/auth.guard.ts
Normal file
30
apps/dafa-web/src/app/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 '@dafa-environment';
|
||||
import { AuthenticationService } from '@dafa-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=${environment.redirectUri}`;
|
||||
}
|
||||
return of(false);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="employee-card">
|
||||
<digi-typography *ngIf="detailedEmployeeData$ | async as detailedEmployeeData; else loadingRef">
|
||||
<div class="employee-card__editcontainer">
|
||||
@@ -90,4 +90,4 @@
|
||||
<span class="dafa__a11y-sr-only">Info saknas</span>
|
||||
</dd>
|
||||
</ng-template>
|
||||
</dafa-logged-in-shell>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -3,10 +3,10 @@ import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { HideTextModule } from '@dafa-shared/components/hide-text/hide-text.module';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
|
||||
import { EmployeeCardComponent } from './employee-card.component';
|
||||
import { LoggedInShellModule } from '../../../../components/logged-in-shell/logged-in-shell.module';
|
||||
import { HideTextModule } from '@dafa-shared/components/hide-text/hide-text.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -14,11 +14,11 @@ import { HideTextModule } from '@dafa-shared/components/hide-text/hide-text.modu
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: EmployeeCardComponent }]),
|
||||
LayoutModule,
|
||||
DigiNgSkeletonBaseModule,
|
||||
DigiNgLayoutExpansionPanelModule,
|
||||
LocalDatePipeModule,
|
||||
HideTextModule,
|
||||
LoggedInShellModule
|
||||
],
|
||||
})
|
||||
export class EmployeeCardModule {}
|
||||
|
||||
@@ -1,158 +1,164 @@
|
||||
<dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="employee-form">
|
||||
<digi-typography>
|
||||
<h1>Skapa nytt konto</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam magna neque, interdum vel massa eget, condimentum
|
||||
rutrum velit. Sed vitae ullamcorper sem. Aliquam malesuada nunc sed purus mollis scelerisque. Curabitur bibendum
|
||||
leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est.
|
||||
</p>
|
||||
</digi-typography>
|
||||
<form [formGroup]="formGroup" (ngSubmit)="submitForm()">
|
||||
<digi-form-error-list
|
||||
class="employee-form__error-list"
|
||||
*ngIf="formGroup.invalid && submitted && formErrors.length"
|
||||
af-heading="Felmeddelanden"
|
||||
>
|
||||
<a *ngFor="let error of formErrors" [routerLink]="" [fragment]="'employee-form-' + error.id">{{
|
||||
error.message
|
||||
}}</a>
|
||||
</digi-form-error-list>
|
||||
<digi-typography>
|
||||
<h1>Skapa nytt konto</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam magna neque, interdum vel massa eget, condimentum
|
||||
rutrum velit. Sed vitae ullamcorper sem. Aliquam malesuada nunc sed purus mollis scelerisque. Curabitur bibendum
|
||||
leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est.
|
||||
</p>
|
||||
</digi-typography>
|
||||
<form [formGroup]="formGroup" (ngSubmit)="submitForm()">
|
||||
<digi-form-error-list
|
||||
class="employee-form__error-list"
|
||||
*ngIf="formGroup.invalid && submitted && formErrors.length"
|
||||
af-heading="Felmeddelanden"
|
||||
>
|
||||
<a *ngFor="let error of formErrors" [routerLink]="" [fragment]="'employee-form-' + error.id">{{
|
||||
error.message
|
||||
}}</a>
|
||||
</digi-form-error-list>
|
||||
|
||||
<div class="employee-form__block">
|
||||
<digi-typography>
|
||||
<h2>Personuppgifter</h2>
|
||||
</digi-typography>
|
||||
<digi-ng-form-input
|
||||
afId="employee-form-firstName"
|
||||
class="employee-form__input"
|
||||
formControlName="firstName"
|
||||
afLabel="Förnamn"
|
||||
afInvalidMessage="Förnamn är obligatoriskt"
|
||||
[afDisableValidStyle]="true"
|
||||
[afInvalid]="firstNameControl.invalid && firstNameControl.dirty"
|
||||
></digi-ng-form-input>
|
||||
<digi-ng-form-input
|
||||
afId="employee-form-lastName"
|
||||
class="employee-form__input"
|
||||
formControlName="lastName"
|
||||
afLabel="Efternamn"
|
||||
afInvalidMessage="Efternamn är obligatoriskt"
|
||||
[afDisableValidStyle]="true"
|
||||
[afInvalid]="lastNameControl.invalid && lastNameControl.dirty"
|
||||
></digi-ng-form-input>
|
||||
<digi-ng-form-input
|
||||
afId="employee-form-ssn"
|
||||
class="employee-form__input"
|
||||
formControlName="ssn"
|
||||
afLabel="Personnummer"
|
||||
[afInvalidMessage]="ssnControl.errors?.message || ''"
|
||||
[afDisableValidStyle]="true"
|
||||
[afInvalid]="ssnControl.invalid && ssnControl.dirty"
|
||||
></digi-ng-form-input>
|
||||
</div>
|
||||
<div class="employee-form__block" *ngIf="services$ | async as services">
|
||||
<fieldset class="employee-form__fieldset">
|
||||
<div class="employee-form__block">
|
||||
<digi-typography>
|
||||
<legend>Tjänster</legend>
|
||||
<h2>Personuppgifter</h2>
|
||||
</digi-typography>
|
||||
<digi-ng-form-input
|
||||
afId="employee-form-firstName"
|
||||
class="employee-form__input"
|
||||
formControlName="firstName"
|
||||
afLabel="Förnamn"
|
||||
afInvalidMessage="Förnamn är obligatoriskt"
|
||||
[afDisableValidStyle]="true"
|
||||
[afInvalid]="firstNameControl.invalid && firstNameControl.dirty"
|
||||
></digi-ng-form-input>
|
||||
<digi-ng-form-input
|
||||
afId="employee-form-lastName"
|
||||
class="employee-form__input"
|
||||
formControlName="lastName"
|
||||
afLabel="Efternamn"
|
||||
afInvalidMessage="Efternamn är obligatoriskt"
|
||||
[afDisableValidStyle]="true"
|
||||
[afInvalid]="lastNameControl.invalid && lastNameControl.dirty"
|
||||
></digi-ng-form-input>
|
||||
<digi-ng-form-input
|
||||
afId="employee-form-ssn"
|
||||
class="employee-form__input"
|
||||
formControlName="ssn"
|
||||
afLabel="Personnummer"
|
||||
[afInvalidMessage]="ssnControl.errors?.message || ''"
|
||||
[afDisableValidStyle]="true"
|
||||
[afInvalid]="ssnControl.invalid && ssnControl.dirty"
|
||||
></digi-ng-form-input>
|
||||
</div>
|
||||
<div class="employee-form__block" *ngIf="services$ | async as services">
|
||||
<fieldset class="employee-form__fieldset">
|
||||
<digi-typography>
|
||||
<legend>Tjänster</legend>
|
||||
</digi-typography>
|
||||
|
||||
<ul class="employee-form__services">
|
||||
<li *ngFor="let service of services; let first = first" class="employee-form__service-item">
|
||||
<digi-form-checkbox
|
||||
[afId]="(first && 'employee-form-services') || undefined"
|
||||
af-variation="primary"
|
||||
[afValidation]="servicesControl.invalid && servicesControl.dirty && 'error'"
|
||||
[afLabel]="service.name"
|
||||
[afValue]="service.id"
|
||||
[afChecked]="servicesControl.value.includes(service)"
|
||||
(afOnChange)="toggleService(service, $event.detail.target.checked)"
|
||||
></digi-form-checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
<digi-form-validation-message
|
||||
class="employee-form__validation-message"
|
||||
*ngIf="servicesControl.invalid && servicesControl.dirty"
|
||||
af-variation="error"
|
||||
<ul class="employee-form__services">
|
||||
<li *ngFor="let service of services; let first = first" class="employee-form__service-item">
|
||||
<digi-form-checkbox
|
||||
[afId]="(first && 'employee-form-services') || undefined"
|
||||
af-variation="primary"
|
||||
[afValidation]="servicesControl.invalid && servicesControl.dirty && 'error'"
|
||||
[afLabel]="service.name"
|
||||
[afValue]="service.id"
|
||||
[afChecked]="servicesControl.value.includes(service)"
|
||||
(afOnChange)="toggleService(service, $event.detail.target.checked)"
|
||||
></digi-form-checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
<digi-form-validation-message
|
||||
class="employee-form__validation-message"
|
||||
*ngIf="servicesControl.invalid && servicesControl.dirty"
|
||||
af-variation="error"
|
||||
>
|
||||
{{ servicesControl.errors.message }}
|
||||
</digi-form-validation-message>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="employee-form__block" *ngIf="authorizations$ | async as authorizations">
|
||||
<fieldset class="employee-form__fieldset">
|
||||
<digi-typography>
|
||||
<legend>Tilldela behörigheter</legend>
|
||||
</digi-typography>
|
||||
|
||||
<ul class="employee-form__authorizations">
|
||||
<li
|
||||
*ngFor="let authorization of authorizations; let first = first"
|
||||
class="employee-form__authorization-item"
|
||||
>
|
||||
<digi-form-checkbox
|
||||
class="employee-form__digi-checkbox"
|
||||
[afId]="(first && 'employee-form-authorizations') || undefined"
|
||||
af-variation="primary"
|
||||
[afValidation]="authorizationsControl.invalid && authorizationsControl.dirty && 'error'"
|
||||
[afLabel]="authorization.name"
|
||||
[afValue]="authorization.id"
|
||||
[afChecked]="authorizationsControl.value.includes(authorization)"
|
||||
(afOnChange)="toggleAuthorization(authorization, $event.detail.target.checked)"
|
||||
></digi-form-checkbox>
|
||||
<digi-button
|
||||
af-variation="secondary"
|
||||
[afAriaLabel]="'Läs mer om ' + authorization.name"
|
||||
af-size="s"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="openDialog(true, authorization.name)"
|
||||
>
|
||||
Läs mer
|
||||
</digi-button>
|
||||
</li>
|
||||
</ul>
|
||||
<digi-form-validation-message
|
||||
class="employee-form__validation-message"
|
||||
*ngIf="authorizationsControl.invalid && authorizationsControl.dirty"
|
||||
af-variation="error"
|
||||
>
|
||||
{{ authorizationsControl.errors.message }}
|
||||
</digi-form-validation-message>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div class="employee-form__footer">
|
||||
<digi-button af-type="reset" af-variation="secondary" (afOnClick)="resetForm($event.detail)"
|
||||
>Avbryt</digi-button
|
||||
>
|
||||
{{ servicesControl.errors.message }}
|
||||
</digi-form-validation-message>
|
||||
</fieldset>
|
||||
</div>
|
||||
<digi-button af-type="submit">Registrera konto</digi-button>
|
||||
</div>
|
||||
|
||||
<div class="employee-form__block" *ngIf="authorizations$ | async as authorizations">
|
||||
<fieldset class="employee-form__fieldset">
|
||||
<digi-typography>
|
||||
<legend>Tilldela behörigheter</legend>
|
||||
</digi-typography>
|
||||
<!-- Modal/ Dialog window -->
|
||||
<digi-ng-dialog
|
||||
[afActive]="toggleDialog"
|
||||
(afOnInactive)="openDialog(false)"
|
||||
(afOnPrimaryClick)="openDialog(false)"
|
||||
[afHeading]="modalAuthInfo.name"
|
||||
afHeadingLevel="h3"
|
||||
afPrimaryButtonText="Stäng"
|
||||
>
|
||||
<p>
|
||||
Behörigheten passar personer som arbetar nära deltagare. Behörigheten kan användas av exempelvis handledare,
|
||||
coacher, studie- och yrkesvägledare, lärare eller annan roll som behöver kunna se information om deltager,
|
||||
kontakta deltagare, planera aktiviteter med deltagre och hantera rapporter för deltagre.
|
||||
</p>
|
||||
|
||||
<ul class="employee-form__authorizations">
|
||||
<li *ngFor="let authorization of authorizations; let first = first"
|
||||
class="employee-form__authorization-item">
|
||||
<digi-form-checkbox
|
||||
class="employee-form__digi-checkbox"
|
||||
[afId]="(first && 'employee-form-authorizations') || undefined"
|
||||
af-variation="primary"
|
||||
[afValidation]="authorizationsControl.invalid && authorizationsControl.dirty && 'error'"
|
||||
[afLabel]="authorization.name"
|
||||
[afValue]="authorization.id"
|
||||
[afChecked]="authorizationsControl.value.includes(authorization)"
|
||||
(afOnChange)="toggleAuthorization(authorization, $event.detail.target.checked)"
|
||||
></digi-form-checkbox>
|
||||
<digi-button af-variation="secondary" [afAriaLabel]="'Läs mer om ' + authorization.name"
|
||||
af-size="s" class="employee-form__read-more"
|
||||
(afOnClick)="openDialog(true, authorization.name)">
|
||||
Läs mer
|
||||
</digi-button>
|
||||
</li>
|
||||
</ul>
|
||||
<digi-form-validation-message
|
||||
class="employee-form__validation-message"
|
||||
*ngIf="authorizationsControl.invalid && authorizationsControl.dirty"
|
||||
af-variation="error"
|
||||
>
|
||||
{{ authorizationsControl.errors.message }}
|
||||
</digi-form-validation-message>
|
||||
</fieldset>
|
||||
</div>
|
||||
<p>Behörigheten ger tillgång till och utföra aktiviteter i följande funktioner i systemet:</p>
|
||||
|
||||
<div class="employee-form__footer">
|
||||
<digi-button af-type="reset" af-variation="secondary" (afOnClick)="resetForm($event.detail)">Avbryt</digi-button>
|
||||
<digi-button af-type="submit">Registrera konto</digi-button>
|
||||
</div>
|
||||
|
||||
<!-- Modal/ Dialog window -->
|
||||
<digi-ng-dialog
|
||||
[afActive]="toggleDialog"
|
||||
(afOnInactive)="openDialog(false)"
|
||||
(afOnPrimaryClick)="openDialog(false)"
|
||||
[afHeading]="modalAuthInfo.name"
|
||||
afHeadingLevel="h3"
|
||||
afPrimaryButtonText="Stäng">
|
||||
<p>
|
||||
Behörigheten passar personer som arbetar nära deltagare.
|
||||
Behörigheten kan användas av exempelvis handledare, coacher, studie- och yrkesvägledare,
|
||||
lärare eller annan roll som behöver kunna se information om deltager, kontakta deltagare,
|
||||
planera aktiviteter med deltagre och hantera rapporter för deltagre.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Behörigheten ger tillgång till och utföra aktiviteter i följande funktioner i systemet:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
- Deltagarlista <br/>
|
||||
- Information om deltagare <br/>
|
||||
- Resultatrapporter <br/>
|
||||
- Slutredovisning <br/>
|
||||
- Informativ rapport <br/>
|
||||
- Skicka välkomstbrev * <br/>
|
||||
- Planera deltagares aktiviteter <br/>
|
||||
- Deltagares schema <br/>
|
||||
- Avvikelserapporter <br/>
|
||||
- Närvaro- och frånvarorapporter <br/><br/>
|
||||
</p>
|
||||
</digi-ng-dialog>
|
||||
</form>
|
||||
</section>
|
||||
</dafa-logged-in-shell>
|
||||
<p>
|
||||
- Deltagarlista <br />
|
||||
- Information om deltagare <br />
|
||||
- Resultatrapporter <br />
|
||||
- Slutredovisning <br />
|
||||
- Informativ rapport <br />
|
||||
- Skicka välkomstbrev * <br />
|
||||
- Planera deltagares aktiviteter <br />
|
||||
- Deltagares schema <br />
|
||||
- Avvikelserapporter <br />
|
||||
- Närvaro- och frånvarorapporter <br /><br />
|
||||
</p>
|
||||
</digi-ng-dialog>
|
||||
</form>
|
||||
</section>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { DigiNgDialogModule } from '@af/digi-ng/_dialog/dialog';
|
||||
import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
|
||||
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
|
||||
import { DigiNgFormInputModule } from '@af/digi-ng/_form/form-input';
|
||||
@@ -8,10 +9,9 @@ import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
|
||||
import { EmployeeFormComponent } from './employee-form.component';
|
||||
import { DigiNgDialogModule } from '@af/digi-ng/_dialog/dialog';
|
||||
import { LoggedInShellModule } from '../../../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -19,6 +19,7 @@ import { LoggedInShellModule } from '../../../../components/logged-in-shell/logg
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: EmployeeFormComponent }]),
|
||||
LayoutModule,
|
||||
ReactiveFormsModule,
|
||||
LocalDatePipeModule,
|
||||
DigiNgFormInputModule,
|
||||
@@ -28,7 +29,6 @@ import { LoggedInShellModule } from '../../../../components/logged-in-shell/logg
|
||||
DigiNgPopoverModule,
|
||||
DigiNgFormCheckboxModule,
|
||||
DigiNgDialogModule,
|
||||
LoggedInShellModule
|
||||
]
|
||||
],
|
||||
})
|
||||
export class EmployeeFormModule {}
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="employees-list__column-head" *ngFor="let column of columnHeaders">
|
||||
<button class="employees-list__sort-button" [id]="'sort-button-' + column" (click)="handleSort(column.key)">
|
||||
<button
|
||||
class="employees-list__sort-button"
|
||||
[attr.id]="'sort-button-' + column.key"
|
||||
(click)="handleSort(column.key)"
|
||||
>
|
||||
{{column.label}}
|
||||
<ng-container *ngIf="sort.key === column">
|
||||
<ng-container *ngIf="sort.key === column.key">
|
||||
<digi-icon-caret-up
|
||||
class="employees-list__sort-icon"
|
||||
*ngIf="sort.order === orderType.ASC"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="employees">
|
||||
<digi-typography>
|
||||
<h1>Personal</h1>
|
||||
@@ -37,4 +37,4 @@
|
||||
<digi-ng-skeleton-base [afCount]="3" afText="Laddar personal"></digi-ng-skeleton-base>
|
||||
</ng-template>
|
||||
</section>
|
||||
</dafa-logged-in-shell>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -5,9 +5,9 @@ import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { EmployeesListModule } from './components/employees-list/employees-list.module';
|
||||
import { EmployeesComponent } from './employees.component';
|
||||
import { LoggedInShellModule } from '../../../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -15,12 +15,12 @@ import { LoggedInShellModule } from '../../../../components/logged-in-shell/logg
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: EmployeesComponent }]),
|
||||
LayoutModule,
|
||||
DigiNgLinkInternalModule,
|
||||
DigiNgSkeletonBaseModule,
|
||||
EmployeesListModule,
|
||||
DigiNgLinkButtonModule,
|
||||
FormsModule,
|
||||
LoggedInShellModule
|
||||
]
|
||||
],
|
||||
})
|
||||
export class EmployeesModule {}
|
||||
|
||||
@@ -1,22 +1,16 @@
|
||||
<dafa-logged-in-shell>
|
||||
<section class="call-off" *ngIf="currentStep$ | async; let currentStep; else loadingRef">
|
||||
<dafa-layout>
|
||||
<section class="call-off" *ngIf="currentStep$ | async; let currentStep; else: loadingRef">
|
||||
<digi-typography>
|
||||
<h2>Välj deltagare att tilldela</h2>
|
||||
<p>Steg {{ currentStep }} av {{ steps }}:</p>
|
||||
</digi-typography>
|
||||
<digi-ng-progress-progressbar
|
||||
[afSteps]="steps"
|
||||
afAriaLabel="An aria label"
|
||||
[afActiveStep]="currentStep">
|
||||
<digi-ng-progress-progressbar [afSteps]="steps" afAriaLabel="An aria label" [afActiveStep]="currentStep">
|
||||
</digi-ng-progress-progressbar>
|
||||
|
||||
<div class="" style="height:300px; padding: 30px 0;">
|
||||
<div class="" style="height: 300px; padding: 30px 0">
|
||||
<ng-container *ngIf="currentStep == 4">
|
||||
<h2>Avropet är sparat</h2>
|
||||
<digi-button
|
||||
af-size="m"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="goToStep1()">
|
||||
<digi-button af-size="m" class="employee-form__read-more" (afOnClick)="goToStep1()">
|
||||
Tillbaka till nya deltagare
|
||||
</digi-button>
|
||||
</ng-container>
|
||||
@@ -28,83 +22,77 @@
|
||||
<h2>Vänligen bekräfta</h2>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="currentStep < 4">
|
||||
<dafa-avrop-table
|
||||
[selectableDeltagareList]="selectableDeltagareList$ | async"
|
||||
[selectedDeltagareListInput]="selectedDeltagareList$ | async"
|
||||
[isLocked]="deltagareListIsLocked$ | async"
|
||||
(changedSelectedDeltagareList)="updateSelectedDeltagareList($event)"
|
||||
[handledare]="selectedHandledare$ | async"
|
||||
[handledareConfirmed]="handledareConfirmed$ | async"
|
||||
></dafa-avrop-table>
|
||||
<dafa-avrop-table
|
||||
[selectableDeltagareList]="selectableDeltagareList$ | async"
|
||||
[selectedDeltagareListInput]="selectedDeltagareList$ | async"
|
||||
[isLocked]="deltagareListIsLocked$ | async"
|
||||
(changedSelectedDeltagareList)="updateSelectedDeltagareList($event)"
|
||||
[handledare]="selectedHandledare$ | async"
|
||||
[handledareConfirmed]="handledareConfirmed$ | async"
|
||||
></dafa-avrop-table>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentStep == 1">
|
||||
<digi-button
|
||||
af-size="m"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="lockSelectedDeltagare()">
|
||||
<digi-button af-size="m" class="employee-form__read-more" (afOnClick)="lockSelectedDeltagare()">
|
||||
Lås deltagare
|
||||
</digi-button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="currentStep == 2">
|
||||
<h2>Välj handledare</h2>
|
||||
<ng-container *ngIf="selectableHandledareList$ | async; let selectableHandledareList; else loadingRefSmall">
|
||||
<select [value]="(selectedHandledare$ | async)?.id ? (selectedHandledare$ | async)?.id : ''" (change)="changeHandledare($event)">
|
||||
<option disabled value="" >Välj handledare</option>
|
||||
<ng-container *ngIf="selectableHandledareList$ | async; let selectableHandledareList; else: loadingRefSmall">
|
||||
<select
|
||||
[value]="(selectedHandledare$ | async)?.id ? (selectedHandledare$ | async)?.id : ''"
|
||||
(change)="changeHandledare($event)"
|
||||
>
|
||||
<option disabled value="">Välj handledare</option>
|
||||
|
||||
<option
|
||||
*ngFor="let selectableHandledare of selectableHandledareList"
|
||||
[value]="selectableHandledare?.id"
|
||||
>{{selectableHandledare?.fullName}}</option>
|
||||
<option *ngFor="let selectableHandledare of selectableHandledareList" [value]="selectableHandledare?.id">
|
||||
{{ selectableHandledare?.fullName }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<span *ngIf="selectableHandledareList.length === 0">Inga handledare har behörighet till alla markerade deltagare</span>
|
||||
<span *ngIf="selectableHandledareList.length === 0"
|
||||
>Inga handledare har behörighet till alla markerade deltagare</span
|
||||
>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<br><br>
|
||||
<digi-button af-variation="secondary"
|
||||
af-size="m"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="unlockSelectedDeltagare()">
|
||||
Tillbaka
|
||||
</digi-button>
|
||||
<br /><br />
|
||||
<digi-button
|
||||
af-variation="secondary"
|
||||
af-size="m"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="confirmHandledare()">
|
||||
(afOnClick)="unlockSelectedDeltagare()"
|
||||
>
|
||||
Tillbaka
|
||||
</digi-button>
|
||||
<digi-button af-size="m" class="employee-form__read-more" (afOnClick)="confirmHandledare()">
|
||||
Tilldela
|
||||
</digi-button>
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="currentStep == 3">
|
||||
<br><br>
|
||||
<digi-button af-variation="secondary"
|
||||
af-size="m"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="unconfirmHandledare()">
|
||||
Tillbaka
|
||||
</digi-button>
|
||||
<br /><br />
|
||||
<digi-button
|
||||
af-variation="secondary"
|
||||
af-size="m"
|
||||
class="employee-form__read-more"
|
||||
(afOnClick)="save()">
|
||||
Spara avrop
|
||||
(afOnClick)="unconfirmHandledare()"
|
||||
>
|
||||
Tillbaka
|
||||
</digi-button>
|
||||
<digi-button af-size="m" class="employee-form__read-more" (afOnClick)="save()"> Spara avrop </digi-button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</dafa-logged-in-shell>
|
||||
|
||||
<ng-template #loadingRef>
|
||||
<digi-ng-skeleton-base [afCount]="3" afText="Laddar personal"></digi-ng-skeleton-base>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #loadingRef>
|
||||
<digi-ng-skeleton-base [afCount]="3" afText="Laddar personal"></digi-ng-skeleton-base>
|
||||
</ng-template>
|
||||
<ng-template #loadingRefSmall>
|
||||
<digi-icon-spinner af-title="Laddar innehåll"></digi-icon-spinner>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #loadingRefSmall>
|
||||
<digi-icon-spinner af-title="Laddar innehåll"></digi-icon-spinner>
|
||||
</ng-template>
|
||||
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
import { DigiNgProgressProgressbarModule } from '@af/digi-ng/_progress/progressbar';
|
||||
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { AvropComponent } from './avrop.component';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
import { DigiNgProgressProgressbarModule } from '@af/digi-ng/_progress/progressbar';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { AvropFiltersComponent } from './avrop-filters/avrop-filters.component';
|
||||
import { AvropTableComponent } from './avrop-table/avrop-table.component';
|
||||
import { AvropTableRowComponent } from './avrop-table/avrop-table-row/avrop-table-row.component';
|
||||
import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
|
||||
import { TemporaryFilterComponent } from './avrop-filters/temporary-filter/temporary-filter.component';
|
||||
import { AvropTableRowComponent } from './avrop-table/avrop-table-row/avrop-table-row.component';
|
||||
import { AvropTableComponent } from './avrop-table/avrop-table.component';
|
||||
import { AvropComponent } from './avrop.component';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [AvropComponent, AvropFiltersComponent, AvropTableComponent, AvropTableRowComponent, TemporaryFilterComponent],
|
||||
declarations: [
|
||||
AvropComponent,
|
||||
AvropFiltersComponent,
|
||||
AvropTableComponent,
|
||||
AvropTableRowComponent,
|
||||
TemporaryFilterComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: AvropComponent }]),
|
||||
LoggedInShellModule,
|
||||
LayoutModule,
|
||||
DigiNgProgressProgressbarModule,
|
||||
DigiNgSkeletonBaseModule,
|
||||
],
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
<digi-typography>
|
||||
<section class="releases">
|
||||
<h1>Ciam landing</h1>
|
||||
|
||||
<p>Redirecting to /......</p>
|
||||
</section>
|
||||
</digi-typography>
|
||||
@@ -1,37 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { first, map, switchMap } from 'rxjs/operators';
|
||||
import { AuthenticationService } from '@dafa-services/api/authentication.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dafa-ciam-landing',
|
||||
templateUrl: './ciam-landing.component.html',
|
||||
styleUrls: ['./ciam-landing.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class CiamLandingComponent implements OnInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private authenticationService: AuthenticationService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.route.queryParams
|
||||
.pipe(
|
||||
first(),
|
||||
map(({ code }) => {
|
||||
if (!code) {
|
||||
throw new Error('Expected CIAM to return "code" in queryparams.');
|
||||
}
|
||||
return code as string;
|
||||
}),
|
||||
switchMap(code => {
|
||||
return this.authenticationService.login$(code);
|
||||
})
|
||||
)
|
||||
.subscribe(() => {
|
||||
void this.router.navigateByUrl('/');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { CiamLandingComponent } from './ciam-landing.component';
|
||||
import { DigiNgButtonModule } from '@af/digi-ng/_button/button';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [CiamLandingComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: CiamLandingComponent }]),
|
||||
DigiNgButtonModule
|
||||
]
|
||||
})
|
||||
export class CiamLandingModule {}
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DigiNgButtonModule } from '@af/digi-ng/_button/button';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LogoutComponent } from './logout.component';
|
||||
import { DigiNgButtonModule } from '@af/digi-ng/_button/button';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
<dafa-logged-in-shell>
|
||||
<section class="messages">Meddelanden funkar!</section>
|
||||
</dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="messages">Meddelanden funkar!</section>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { MessagesComponent } from './messages.component';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [MessagesComponent],
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: MessagesComponent }]), LoggedInShellModule]
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: MessagesComponent }]), LayoutModule],
|
||||
})
|
||||
export class MessagesModule {}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<digi-typography>
|
||||
<section class="login__wrapper">
|
||||
<section class="mock-login">
|
||||
<h1>Mock login</h1>
|
||||
<p>Simulera att man loggar in och blir redirectad till /ciam-landing med en Authorization-code som sedan används för att hämta authentication-token:</p>
|
||||
<digi-ng-button [routerLink]="'/ciam-landing'" [queryParams]="{code: 'auth_code_from_CIAM_with_all_permissions'}">
|
||||
<p>
|
||||
Simulera att man loggar in och blir redirectad till startsidan med en Authorization-code som sedan används för att
|
||||
hämta authentication-token:
|
||||
</p>
|
||||
<digi-ng-button routerLink="/" [queryParams]="{ code: 'auth_code_from_CIAM_with_all_permissions' }">
|
||||
Logga in med fullständiga rättigheter
|
||||
</digi-ng-button>
|
||||
</section>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.login__wrapper {
|
||||
.mock-login {
|
||||
margin: 5rem;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { DigiNgButtonModule } from '@af/digi-ng/_button/button';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { MockLoginComponent } from './mock-login.component';
|
||||
import { DigiNgButtonModule } from '@af/digi-ng/_button/button';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<dafa-logged-in-shell>
|
||||
<digi-typography>
|
||||
<section class="page-not-found">
|
||||
<h1>Oj då! Vi kan inte hitta sidan.</h1>
|
||||
<p>Det kan bero på att länken du använder är felaktig eller att sidan inte längre finns.</p>
|
||||
<a class="dafa__link dafa__link--with-icon dafa__link--ignore-visited" routerLink="/">
|
||||
<digi-icon-arrow-left class="dafa__digi-icon"></digi-icon-arrow-left>
|
||||
Gå tillbaka till startsidan
|
||||
</a>
|
||||
</section>
|
||||
</digi-typography>
|
||||
</dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<digi-typography>
|
||||
<section class="page-not-found">
|
||||
<h1>Oj då! Vi kan inte hitta sidan.</h1>
|
||||
<p>Det kan bero på att länken du använder är felaktig eller att sidan inte längre finns.</p>
|
||||
<a class="dafa__link dafa__link--with-icon dafa__link--ignore-visited" routerLink="/">
|
||||
<digi-icon-arrow-left class="dafa__digi-icon"></digi-icon-arrow-left>
|
||||
Gå tillbaka till startsidan
|
||||
</a>
|
||||
</section>
|
||||
</digi-typography>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { PageNotFoundComponent } from './page-not-found.component';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [PageNotFoundComponent],
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: PageNotFoundComponent }]), LoggedInShellModule]
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: PageNotFoundComponent }]), LayoutModule],
|
||||
})
|
||||
export class PageNotFoundModule {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="participant-card">
|
||||
<digi-typography *ngIf="detailedParticipantData$ | async as detailedParticipantData; else loadingRef">
|
||||
<header class="participant-card__header">
|
||||
@@ -54,4 +54,4 @@
|
||||
<span class="dafa__a11y-sr-only">Info saknas</span>
|
||||
</dd>
|
||||
</ng-template>
|
||||
</dafa-logged-in-shell>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -4,8 +4,8 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { BackLinkModule } from '@dafa-shared/components/back-link/back-link.module';
|
||||
import { IconModule } from '@dafa-shared/components/icon/icon.module';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { ParticipantCardComponent } from './participant-card.component';
|
||||
import { LoggedInShellModule } from '../../../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -13,7 +13,7 @@ import { LoggedInShellModule } from '../../../../components/logged-in-shell/logg
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: ParticipantCardComponent }]),
|
||||
LoggedInShellModule,
|
||||
LayoutModule,
|
||||
DigiNgLinkInternalModule,
|
||||
IconModule,
|
||||
BackLinkModule,
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
<dafa-logged-in-shell>
|
||||
<section class="participants">
|
||||
<digi-typography>
|
||||
<h1>Mina deltagare</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam magna neque, interdum vel massa eget, condimentum
|
||||
rutrum velit. Sed vitae ullamcorper sem. Aliquam malesuada nunc sed purus mollis scelerisque. Curabitur bibendum
|
||||
leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est.
|
||||
</p>
|
||||
</digi-typography>
|
||||
<dafa-layout>
|
||||
<section class="participants">
|
||||
<digi-typography>
|
||||
<h1>Mina deltagare</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam magna neque, interdum vel massa eget, condimentum
|
||||
rutrum velit. Sed vitae ullamcorper sem. Aliquam malesuada nunc sed purus mollis scelerisque. Curabitur bibendum
|
||||
leo quis ante porttitor tincidunt. Nam tincidunt imperdiet tortor eu suscipit. Maecenas ut dui est.
|
||||
</p>
|
||||
</digi-typography>
|
||||
|
||||
<form class="participants__search-wrapper" (ngSubmit)="handleSearchSubmit()">
|
||||
<digi-form-input-search
|
||||
af-label="Sök deltagare"
|
||||
af-label-description="Sök på namn eller ärendenummer"
|
||||
(afOnInput)="handleSearchInput($event)"
|
||||
></digi-form-input-search>
|
||||
</form>
|
||||
<form class="participants__search-wrapper" (ngSubmit)="handleSearchSubmit()">
|
||||
<digi-form-input-search
|
||||
af-label="Sök deltagare"
|
||||
af-label-description="Sök på namn eller ärendenummer"
|
||||
(afOnInput)="handleSearchInput($event)"
|
||||
></digi-form-input-search>
|
||||
</form>
|
||||
|
||||
<section class="participants__list">
|
||||
<h2>Pågående tjänst</h2>
|
||||
<dafa-participants-list
|
||||
*ngIf="activeParticipants$ | async as participants; else loadingRef"
|
||||
[participants]="participants"
|
||||
[sortBy]="activeParticipantsSortBy$ | async"
|
||||
(sorted)="handleActiveParticipantsSort($event)"
|
||||
></dafa-participants-list>
|
||||
<section class="participants__list">
|
||||
<h2>Pågående tjänst</h2>
|
||||
<dafa-participants-list
|
||||
*ngIf="activeParticipants$ | async as participants; else loadingRef"
|
||||
[participants]="participants"
|
||||
[sortBy]="activeParticipantsSortBy$ | async"
|
||||
(sorted)="handleActiveParticipantsSort($event)"
|
||||
></dafa-participants-list>
|
||||
</section>
|
||||
|
||||
<section class="participants__list">
|
||||
<h2>För uppföljning</h2>
|
||||
<dafa-participants-list
|
||||
*ngIf="followUpParticipants$ | async as participants; else loadingRef"
|
||||
[participants]="participants"
|
||||
[sortBy]="followUpParticipantsSortBy$ | async"
|
||||
(sorted)="handleFollowUpParticipantsSort($event)"
|
||||
></dafa-participants-list>
|
||||
</section>
|
||||
|
||||
<ng-template #loadingRef>
|
||||
<digi-ng-skeleton-base [afCount]="3" afText="Laddar deltagare"></digi-ng-skeleton-base>
|
||||
</ng-template>
|
||||
</section>
|
||||
|
||||
<section class="participants__list">
|
||||
<h2>För uppföljning</h2>
|
||||
<dafa-participants-list
|
||||
*ngIf="followUpParticipants$ | async as participants; else loadingRef"
|
||||
[participants]="participants"
|
||||
[sortBy]="followUpParticipantsSortBy$ | async"
|
||||
(sorted)="handleFollowUpParticipantsSort($event)"
|
||||
></dafa-participants-list>
|
||||
</section>
|
||||
|
||||
<ng-template #loadingRef>
|
||||
<digi-ng-skeleton-base [afCount]="3" afText="Laddar deltagare"></digi-ng-skeleton-base>
|
||||
</ng-template>
|
||||
</section>
|
||||
</dafa-logged-in-shell>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { DigiNgSkeletonBaseModule } from '@af/digi-ng/_skeleton/skeleton-base';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { ParticipantsListModule } from './components/participants-list/participants-list.module';
|
||||
import { ParticipantsRoutingModule } from './participants-routing.module';
|
||||
import { ParticipantsComponent } from './participants.component';
|
||||
@@ -12,11 +12,11 @@ import { ParticipantsComponent } from './participants.component';
|
||||
declarations: [ParticipantsComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
LayoutModule,
|
||||
ParticipantsRoutingModule,
|
||||
FormsModule,
|
||||
DigiNgSkeletonBaseModule,
|
||||
ParticipantsListModule,
|
||||
LoggedInShellModule,
|
||||
],
|
||||
})
|
||||
export class ParticipantsModule {}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<dafa-logged-in-shell>
|
||||
<digi-typography>
|
||||
<section class="releases">
|
||||
<h1>Releaser</h1>
|
||||
<p>
|
||||
Alla förändringar i applikationen blir dokumenterade på den här sidan. Versionen som ligger högst upp är den som
|
||||
är aktuell just nu.
|
||||
</p>
|
||||
<markdown src="assets/CHANGELOG.md"></markdown>
|
||||
</section>
|
||||
</digi-typography>
|
||||
</dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<digi-typography>
|
||||
<section class="releases">
|
||||
<h1>Releaser</h1>
|
||||
<p>
|
||||
Alla förändringar i applikationen blir dokumenterade på den här sidan. Versionen som ligger högst upp är den som
|
||||
är aktuell just nu.
|
||||
</p>
|
||||
<markdown src="assets/CHANGELOG.md"></markdown>
|
||||
</section>
|
||||
</digi-typography>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
import { ReleasesComponent } from './releases.component';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -12,7 +12,7 @@ import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-
|
||||
CommonModule,
|
||||
MarkdownModule.forChild(),
|
||||
RouterModule.forChild([{ path: '', component: ReleasesComponent }]),
|
||||
LoggedInShellModule
|
||||
]
|
||||
LayoutModule,
|
||||
],
|
||||
})
|
||||
export class ReleasesModule {}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<dafa-logged-in-shell>
|
||||
<section class="settings">Inställningar funkar!</section>
|
||||
</dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="settings">Inställningar funkar!</section>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { SettingsComponent } from './settings.component';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SettingsComponent],
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: SettingsComponent }]), LoggedInShellModule]
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: SettingsComponent }]), LayoutModule],
|
||||
})
|
||||
export class SettingsModule {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="start">
|
||||
<digi-typography>
|
||||
<h1>Välkommen till Mina Sidor FA</h1>
|
||||
@@ -33,4 +33,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</dafa-logged-in-shell>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { DigiNgCardModule } from '@af/digi-ng/_card/card';
|
||||
import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal';
|
||||
import { DigiNgNotificationAlertModule } from '@af/digi-ng/_notification/notification-alert';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { StartComponent } from './start.component';
|
||||
import { DigiNgCardModule } from '@af/digi-ng/_card/card';
|
||||
import { DigiNgNotificationAlertModule } from '@af/digi-ng/_notification/notification-alert';
|
||||
import { DigiNgLinkInternalModule } from '@af/digi-ng/_link/link-internal';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
@@ -13,10 +13,10 @@ import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule.forChild([{ path: '', component: StartComponent }]),
|
||||
LayoutModule,
|
||||
DigiNgCardModule,
|
||||
DigiNgNotificationAlertModule,
|
||||
DigiNgLinkInternalModule,
|
||||
LoggedInShellModule
|
||||
]
|
||||
],
|
||||
})
|
||||
export class StartModule {}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<dafa-logged-in-shell>
|
||||
<dafa-layout>
|
||||
<section class="statistics">Statistik funkar!</section>
|
||||
</dafa-logged-in-shell>
|
||||
</dafa-layout>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { LayoutModule } from '@dafa-shared/components/layout/layout.module';
|
||||
import { StatisticsComponent } from './statistics.component';
|
||||
import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [StatisticsComponent],
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: StatisticsComponent }]), LoggedInShellModule]
|
||||
imports: [CommonModule, RouterModule.forChild([{ path: '', component: StatisticsComponent }]), LayoutModule],
|
||||
})
|
||||
export class StatisticsModule {}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthInterceptor implements HttpInterceptor {
|
||||
constructor(private auth: AuthenticationService) {}
|
||||
|
||||
intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||
const idToken = this.auth.getAuthorizationToken();
|
||||
const idToken = this.auth.currentAuthorizationToken;
|
||||
|
||||
if (idToken) {
|
||||
const cloned = req.clone({
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '@dafa-environment';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
import {
|
||||
AuthenticationApiResponse,
|
||||
AuthenticationResult,
|
||||
mapAuthApiResponseToAuthenticationResult,
|
||||
} from '@dafa-models/authentication.model';
|
||||
import { add, isBefore } from 'date-fns';
|
||||
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
|
||||
import { map, tap } from 'rxjs/operators';
|
||||
|
||||
const API_HEADERS = { headers: environment.api.headers };
|
||||
|
||||
@@ -16,14 +16,29 @@ const API_HEADERS = { headers: environment.api.headers };
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AuthenticationService {
|
||||
private _token$ = new BehaviorSubject<string>(null);
|
||||
private _expiration$ = new BehaviorSubject<number>(null);
|
||||
|
||||
isLoggedIn$: Observable<boolean> = combineLatest([this._token$, this._expiration$]).pipe(
|
||||
map(([token, expiration]) => {
|
||||
if (token && expiration) {
|
||||
return isBefore(new Date(), expiration);
|
||||
}
|
||||
|
||||
return false;
|
||||
})
|
||||
);
|
||||
|
||||
private static _authTokenApiUrl(code: string): string {
|
||||
return `${environment.api.url}/get-token?code=${code}`;
|
||||
return `${environment.api.url}/auth/token?accessCode=${code}`;
|
||||
}
|
||||
|
||||
private static _setSession(authenticationResult: AuthenticationResult): void {
|
||||
private _setSession(authenticationResult: AuthenticationResult): void {
|
||||
const expiresAt = add(new Date(), { seconds: authenticationResult.expiresIn });
|
||||
|
||||
this._token$.next(authenticationResult.idToken);
|
||||
localStorage.setItem('id_token', authenticationResult.idToken);
|
||||
this._expiration$.next(expiresAt.valueOf());
|
||||
localStorage.setItem('expires_at', JSON.stringify(expiresAt.valueOf()));
|
||||
}
|
||||
|
||||
@@ -31,31 +46,37 @@ export class AuthenticationService {
|
||||
return this.httpClient
|
||||
.get<AuthenticationApiResponse>(AuthenticationService._authTokenApiUrl(authorizationCodeFromCiam), API_HEADERS)
|
||||
.pipe(
|
||||
map(response => mapAuthApiResponseToAuthenticationResult(response.data)),
|
||||
map(response => mapAuthApiResponseToAuthenticationResult(response)),
|
||||
tap(authenticationResult => {
|
||||
AuthenticationService._setSession(authenticationResult);
|
||||
this._setSession(authenticationResult);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
isLoggedIn(): boolean {
|
||||
return isBefore(new Date(), this.getExpiration());
|
||||
}
|
||||
|
||||
isLoggedOut(): boolean {
|
||||
return !this.isLoggedIn();
|
||||
}
|
||||
|
||||
getAuthorizationToken(): string {
|
||||
return localStorage.getItem('id_token');
|
||||
}
|
||||
|
||||
getExpiration(): number {
|
||||
private _getLocalStorageData(): { id_token: string; expires_at: number } {
|
||||
const id_token = localStorage.getItem('id_token');
|
||||
const expiration = localStorage.getItem('expires_at');
|
||||
return JSON.parse(expiration) as number;
|
||||
|
||||
return id_token && expiration
|
||||
? {
|
||||
id_token,
|
||||
expires_at: +JSON.parse(expiration),
|
||||
}
|
||||
: null;
|
||||
}
|
||||
|
||||
constructor(private httpClient: HttpClient) {}
|
||||
get currentAuthorizationToken(): string {
|
||||
return this._token$.getValue();
|
||||
}
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
const localStorageData = this._getLocalStorageData();
|
||||
|
||||
if (localStorageData) {
|
||||
this._token$.next(localStorageData.id_token);
|
||||
this._expiration$.next(localStorageData.expires_at);
|
||||
}
|
||||
}
|
||||
|
||||
logout(): void {
|
||||
localStorage.removeItem('id_token');
|
||||
|
||||
@@ -11,8 +11,8 @@ const API_HEADERS = { headers: environment.api.headers };
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UserService {
|
||||
private _userApiUrl = `${environment.api.url}/currentUser`;
|
||||
public currentUser$: Observable<User> = this.httpClient
|
||||
private _userApiUrl = `${environment.api.url}/auth`;
|
||||
public user$: Observable<User> = this.httpClient
|
||||
.get<UserApiResponse>(this._userApiUrl, API_HEADERS)
|
||||
.pipe(map(response => mapUserApiResponseToUser(response.data)));
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
</a>
|
||||
</div>
|
||||
<ul class="navigation__list dafa__hide-on-print">
|
||||
<li class="navigation__item navigation__item--user" *ngIf="currentUser">
|
||||
<span class="navigation__text">{{ currentUser.fullName }}</span>
|
||||
<li class="navigation__item navigation__item--user">
|
||||
<span *ngIf="user" class="navigation__text">{{ user.fullName }}</span>
|
||||
<dafa-icon [icon]="iconType.USER" size="l"></dafa-icon>
|
||||
</li>
|
||||
<li class="navigation__item">
|
||||
@@ -21,16 +21,5 @@
|
||||
<span class="dafa__a11y-sr-only">Inställningar</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- <li class="navigation__item">
|
||||
<a
|
||||
class="navigation__link"
|
||||
[routerLink]="['/']"
|
||||
[routerLinkActive]="['navigation__link--active']"
|
||||
[routerLinkActiveOptions]="{ exact: true }"
|
||||
>
|
||||
<dafa-icon [icon]="iconType.HOME" size="l"></dafa-icon>
|
||||
<span class="navigation__text">Startsida</span>
|
||||
</a>
|
||||
</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
@@ -9,6 +9,6 @@ import { User } from '@dafa-models/user.model';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class NavigationComponent {
|
||||
@Input() currentUser: User;
|
||||
@Input() user: User;
|
||||
iconType = IconType;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="dafa">
|
||||
<div class="dafa" *ngIf="isLoggedIn$ | async">
|
||||
<dafa-skip-to-content mainContentId="dafa-main-content"></dafa-skip-to-content>
|
||||
|
||||
<header class="dafa__header">
|
||||
<dafa-navigation *ngIf="isLoggedIn" [currentUser]="currentUser$ | async"></dafa-navigation>
|
||||
<dafa-navigation [user]="user$ | async"></dafa-navigation>
|
||||
</header>
|
||||
|
||||
<dafa-sidebar class="dafa__sidebar"></dafa-sidebar>
|
||||
@@ -12,10 +12,8 @@
|
||||
[afItems]="breadcrumbsItems"
|
||||
></digi-ng-navigation-breadcrumbs>
|
||||
|
||||
<ng-content></ng-content>
|
||||
|
||||
<ng-content></ng-content>
|
||||
</main>
|
||||
|
||||
<dafa-footer class="dafa__footer"></dafa-footer>
|
||||
</div>
|
||||
<dafa-toast-list></dafa-toast-list>
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -1,47 +1,54 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { NavigationBreadcrumbsItem } from '@af/digi-ng/_navigation/navigation-breadcrumbs';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { User } from '@dafa-models/user.model';
|
||||
import { NavigationEnd, Router } from '@angular/router';
|
||||
import { UserService } from '@dafa-services/api/user.service';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { mapPathsToBreadcrumbs } from '@dafa-utils/map-paths-to-breadcrumbs.util';
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
|
||||
import { UnsubscribeDirective } from '@dafa-directives/unsubscribe.directive';
|
||||
import { User } from '@dafa-models/user.model';
|
||||
import { AuthenticationService } from '@dafa-services/api/authentication.service';
|
||||
import { environment } from '@dafa-environment';
|
||||
import { UserService } from '@dafa-services/api/user.service';
|
||||
import { mapPathsToBreadcrumbs } from '@dafa-utils/map-paths-to-breadcrumbs.util';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { filter, switchMap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'dafa-logged-in-shell',
|
||||
templateUrl: './logged-in-shell.component.html',
|
||||
styleUrls: ['./logged-in-shell.component.scss'],
|
||||
selector: 'dafa-layout',
|
||||
templateUrl: './layout.component.html',
|
||||
styleUrls: ['./layout.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class LoggedInShellComponent extends UnsubscribeDirective {
|
||||
export class LayoutComponent extends UnsubscribeDirective {
|
||||
private startBreadcrumb: NavigationBreadcrumbsItem = {
|
||||
text: 'Start',
|
||||
routerLink: '/',
|
||||
};
|
||||
private _breadcrumbsItems$ = new BehaviorSubject<NavigationBreadcrumbsItem[]>([this.startBreadcrumb]);
|
||||
public currentUser$: Observable<User> = this.userService.currentUser$;
|
||||
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();
|
||||
}
|
||||
|
||||
get isLoggedIn(): boolean {
|
||||
return this.authService.isLoggedIn();
|
||||
}
|
||||
|
||||
constructor(private router: Router, private authService: AuthenticationService, private userService: UserService) {
|
||||
constructor(
|
||||
private router: Router,
|
||||
private activatedRoute: ActivatedRoute,
|
||||
private authService: AuthenticationService,
|
||||
private userService: UserService
|
||||
) {
|
||||
super();
|
||||
|
||||
if (this.authService.isLoggedOut()) {
|
||||
void this.router.navigateByUrl(environment.loginUrl);
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -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 {}
|
||||
11
apps/dafa-web/src/environments/environment.api.ts
Normal file
11
apps/dafa-web/src/environments/environment.api.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export const environment = {
|
||||
environment: 'api',
|
||||
clientId: '5d08c2e4-763e-42f6-b858-24e4773bb83d',
|
||||
redirectUri: 'http://localhost:4200',
|
||||
loginUrl: 'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid',
|
||||
production: false,
|
||||
api: {
|
||||
url: '/api',
|
||||
headers: {},
|
||||
},
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
export const environment = {
|
||||
loginUrl:
|
||||
// eslint-disable-next-line max-len
|
||||
'https://ciam-test.arbetsformedlingen.se:8443/uas/oauth2/authorization?response_type=code&scope=openid&redirect_uri=https://localhost:4200/ciam-landing&client_id=5d08c2e4-763e-42f6-b858-24e4773bb83d',
|
||||
production: false,
|
||||
api: {
|
||||
url: '/api',
|
||||
headers: {},
|
||||
},
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
export const environment = {
|
||||
production: false,
|
||||
api: {
|
||||
meet: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/meettest/v1',
|
||||
default: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/v1/data',
|
||||
url: '/api',
|
||||
headers: {
|
||||
Authorization: 'Basic dGVzdHVzZXIxOmRhZmFAMTIz', // user: testuser1, password: dafa@123
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,8 @@
|
||||
export const environment = {
|
||||
loginUrl: 'mock-login',
|
||||
environment: 'local',
|
||||
clientId: '',
|
||||
redirectUri: '',
|
||||
loginUrl: '/mock-login',
|
||||
production: false,
|
||||
api: {
|
||||
url: '/api',
|
||||
|
||||
Reference in New Issue
Block a user