diff --git a/apps/dafa-web/src/app/app-routing.module.ts b/apps/dafa-web/src/app/app-routing.module.ts index 62e4727..e3f4280 100644 --- a/apps/dafa-web/src/app/app-routing.module.ts +++ b/apps/dafa-web/src/app/app-routing.module.ts @@ -21,7 +21,7 @@ const routes: Routes = [ { path: 'avrop', data: { title: 'Avrop' }, - loadChildren: () => import('./pages/call-off/call-off.module').then(m => m.CallOffModule), + loadChildren: () => import('./pages/avrop/avrop.module').then(m => m.AvropModule), }, { path: 'meddelanden', diff --git a/apps/dafa-web/src/app/app.module.ts b/apps/dafa-web/src/app/app.module.ts index 4aeaf35..ffcd494 100644 --- a/apps/dafa-web/src/app/app.module.ts +++ b/apps/dafa-web/src/app/app.module.ts @@ -13,6 +13,7 @@ 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], @@ -28,6 +29,7 @@ import { AuthInterceptor } from '@dafa-services/api/auth.interceptor'; FooterModule, MarkdownModule.forRoot({ loader: HttpClient }), DigiNgNavigationBreadcrumbsModule, + AvropModule, ], providers: [ { diff --git a/apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.module.ts b/apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.module.ts index f24fc0a..808e94e 100644 --- a/apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.module.ts +++ b/apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.module.ts @@ -7,24 +7,20 @@ 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 + ToastListModule, ], + declarations: [LoggedInShellComponent], + exports: [LoggedInShellComponent], }) -export class LoggedInShellModule { } +export class LoggedInShellModule {} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.html b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.html new file mode 100644 index 0000000..5239d48 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.html @@ -0,0 +1,11 @@ + +
+ + + + + + + +
+

diff --git a/apps/dafa-web/src/app/pages/call-off/call-off.component.scss b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.scss similarity index 100% rename from apps/dafa-web/src/app/pages/call-off/call-off.component.scss rename to apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.scss diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.spec.ts b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.spec.ts new file mode 100644 index 0000000..46f2dca --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AvropFiltersComponent } from './avrop-filters.component'; + +describe('AvropFiltersComponent', () => { + let component: AvropFiltersComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AvropFiltersComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AvropFiltersComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.ts b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.ts new file mode 100644 index 0000000..ae2cb8a --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-filters/avrop-filters.component.ts @@ -0,0 +1,34 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { AvropService } from '../avrop.service'; +import { Observable } from 'rxjs'; +import { Deltagare } from '../models/Deltagare'; +import { MultiselectFilterOption } from '../models/AvropFilterOptions'; + +@Component({ + selector: 'dafa-avrop-filters', + templateUrl: './avrop-filters.component.html', + styleUrls: ['./avrop-filters.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AvropFiltersComponent implements OnInit { + selectableTjanster$: Observable = this.avropService.selectableTjanster$; + selectableUtforandeVerksamheter$: Observable = this.avropService + .selectableUtforandeVerksamheter$; + selectableKommuner$: Observable = this.avropService.selectableKommuner$; + + constructor(private avropService: AvropService) {} + + ngOnInit(): void {} + + updateSelectedTjanster(filterOptions: MultiselectFilterOption[]) { + this.avropService.setSelectedTjanster(filterOptions); + } + + updateSelectedUtforandeVerksamheter(filterOptions: MultiselectFilterOption[]) { + this.avropService.setSelectedUtforandeVerksamheter(filterOptions); + } + + updateSelectedKommuner(filterOptions: MultiselectFilterOption[]) { + this.avropService.setSelectedKommuner(filterOptions); + } +} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.html b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.html new file mode 100644 index 0000000..3de901b --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.html @@ -0,0 +1,10 @@ +
+ {{filterLabel}} + + + + Spara +
diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.scss b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.spec.ts b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.spec.ts new file mode 100644 index 0000000..4de8eed --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TemporaryFilterComponent } from './temporary-filter.component'; + +describe('TemporaryFilterComponent', () => { + let component: TemporaryFilterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TemporaryFilterComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(TemporaryFilterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.ts b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.ts new file mode 100644 index 0000000..9c6fdf9 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-filters/temporary-filter/temporary-filter.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit, ChangeDetectionStrategy, Input, Output } from '@angular/core'; +import { MultiselectFilterOption } from '../../models/AvropFilterOptions'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { Deltagare } from '../../models/Deltagare'; +import { EventEmitter } from '@angular/core'; + +@Component({ + selector: 'dafa-temporary-filter', + templateUrl: './temporary-filter.component.html', + styleUrls: ['./temporary-filter.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TemporaryFilterComponent implements OnInit { + private _selectedAvropFilterOption$: BehaviorSubject; + selectedAvropFilterOptionState$: Observable; + + @Input() filterLabel: string; + @Input() filterOptions: MultiselectFilterOption[]; + @Input() selectedOptions: MultiselectFilterOption[]; + @Output() selectedOptionsChange = new EventEmitter(); + + // THIS SHOULD BE REPLACED BY DIGI COMPONENT + constructor() {} + + ngOnInit(): void { + this._selectedAvropFilterOption$ = new BehaviorSubject(this.selectedOptions); + this.selectedAvropFilterOptionState$ = this._selectedAvropFilterOption$.asObservable(); + } + + isSelected(filterOption: MultiselectFilterOption): boolean { + return this.selectedOptions?.includes(filterOption) ?? false; + } + + setOptionState(filterOption: MultiselectFilterOption, isSelected: boolean) { + if (isSelected) { + return this._selectedAvropFilterOption$.next([...(this._selectedAvropFilterOption$.value ?? []), filterOption]); + } + return this._selectedAvropFilterOption$.next( + this._selectedAvropFilterOption$.value?.filter(item => item != filterOption) ?? [] + ); + } + + emitSelectedOptions() { + this.selectedOptionsChange.emit(this._selectedAvropFilterOption$.value); + } +} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-service.service.spec.ts b/apps/dafa-web/src/app/pages/avrop/avrop-service.service.spec.ts new file mode 100644 index 0000000..44b01c9 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-service.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AvropService } from './avrop.service'; + +describe('AvropServiceService', () => { + let service: AvropService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AvropService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.html b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.html new file mode 100644 index 0000000..68f2e32 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.html @@ -0,0 +1,12 @@ +
+ Deltagare: {{deltagare?.fullName}}
+ handledare: {{handledare?.fullName}} + + + +
+
diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.scss b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.component.spec.ts b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.spec.ts similarity index 53% rename from apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.component.spec.ts rename to apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.spec.ts index 46bed5e..3aa2547 100644 --- a/apps/dafa-web/src/app/components/logged-in-shell/logged-in-shell.component.spec.ts +++ b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.spec.ts @@ -1,20 +1,20 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { LoggedInShellComponent } from './logged-in-shell.component'; +import { AvropTableRowComponent } from './avrop-table-row.component'; -describe('LoggedInShellComponent', () => { - let component: LoggedInShellComponent; - let fixture: ComponentFixture; +describe('AvropTableRowComponent', () => { + let component: AvropTableRowComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ LoggedInShellComponent ] + declarations: [ AvropTableRowComponent ] }) .compileComponents(); }); beforeEach(() => { - fixture = TestBed.createComponent(LoggedInShellComponent); + fixture = TestBed.createComponent(AvropTableRowComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.ts b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.ts new file mode 100644 index 0000000..146f3c1 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table-row/avrop-table-row.component.ts @@ -0,0 +1,26 @@ +import { EventEmitter } from '@angular/core'; +import { Component, OnInit, ChangeDetectionStrategy, Input, Output } from '@angular/core'; +import { Deltagare } from '../../models/Deltagare'; +import { Handledare } from '../../models/Handledare'; + +@Component({ + selector: 'dafa-avrop-table-row', + templateUrl: './avrop-table-row.component.html', + styleUrls: ['./avrop-table-row.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AvropTableRowComponent implements OnInit { + @Input() deltagare: Deltagare; + @Input() isSelected: boolean; + @Input() isLocked: boolean; + @Output() isSelectedChange = new EventEmitter(); + @Input() handledare: Handledare; + @Input() handledareConfirmed: boolean; + constructor() {} + + ngOnInit(): void {} + + emitSelectionChange(isSelected: boolean) { + this.isSelectedChange.emit(isSelected); + } +} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.html b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.html new file mode 100644 index 0000000..36e63a8 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.html @@ -0,0 +1,9 @@ + diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.scss b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.spec.ts b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.spec.ts new file mode 100644 index 0000000..12e80e7 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AvropTableComponent } from './avrop-table.component'; + +describe('AvropTableComponent', () => { + let component: AvropTableComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AvropTableComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AvropTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.ts b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.ts new file mode 100644 index 0000000..a3d4150 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop-table/avrop-table.component.ts @@ -0,0 +1,52 @@ +import { Component, OnInit, ChangeDetectionStrategy, Input, Output, EventEmitter } from '@angular/core'; +import { Deltagare } from '../models/Deltagare'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { filter } from 'rxjs/operators'; +import { Handledare } from '../models/Handledare'; + +@Component({ + selector: 'dafa-avrop-table', + templateUrl: './avrop-table.component.html', + styleUrls: ['./avrop-table.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AvropTableComponent implements OnInit { + private _selectedDeltagare$ = new BehaviorSubject(null); + selectedDeltagareState$: Observable = this._selectedDeltagare$.asObservable(); + + @Input() selectableDeltagareList: Deltagare[]; + @Input() selectedDeltagareListInput: Deltagare[]; + @Input() handledare: Handledare; + @Input() isLocked: boolean; + @Input() handledareConfirmed: boolean; + @Output() changedSelectedDeltagareList = new EventEmitter(); + + get deltagareRows(): Deltagare[] { + return this.isLocked ? this.selectedDeltagareListInput : this.selectableDeltagareList; + } + + constructor() {} + + ngOnInit(): void { + this._selectedDeltagare$ + .pipe(filter(x => !!x)) + .subscribe(selectedDeltagare => this.changedSelectedDeltagareList.emit(selectedDeltagare)); + // TODO lägg till unusubscribeOnDestroy + } + + isSelected(deltagare: Deltagare): boolean { + return this.selectedDeltagareListInput?.includes(deltagare) ?? false; + } + + isSelectedChange(deltagare: Deltagare, isSelected: boolean): void { + if (isSelected) { + return this._selectedDeltagare$.next([ + ...(this._selectedDeltagare$.value?.filter(deltagareInList => deltagareInList != deltagare) ?? []), + deltagare, + ]); + } + return this._selectedDeltagare$.next( + this._selectedDeltagare$.value?.filter(deltagareInList => deltagareInList != deltagare) ?? [] + ); + } +} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop.component.html b/apps/dafa-web/src/app/pages/avrop/avrop.component.html new file mode 100644 index 0000000..994afea --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop.component.html @@ -0,0 +1,110 @@ + +
+ +

Välj deltagare att tilldela

+

Steg {{ currentStep }} av {{ steps }}:

+
+ + + +
+ +

Avropet är sparat

+ + Tillbaka till nya deltagare + +
+ + + + + +

Vänligen bekräfta

+
+ + + + + + + Lås deltagare + + + + +

Välj handledare

+ + + + Inga handledare har behörighet till alla markerade deltagare + + + +

+ + Tillbaka + + + Tilldela + +
+ +
+

+ + Tillbaka + + + Spara avrop + +
+
+
+
+ + + + + + + + + + + +
diff --git a/apps/dafa-web/src/app/pages/avrop/avrop.component.scss b/apps/dafa-web/src/app/pages/avrop/avrop.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/apps/dafa-web/src/app/pages/call-off/call-off.component.spec.ts b/apps/dafa-web/src/app/pages/avrop/avrop.component.spec.ts similarity index 68% rename from apps/dafa-web/src/app/pages/call-off/call-off.component.spec.ts rename to apps/dafa-web/src/app/pages/avrop/avrop.component.spec.ts index c189e6e..e5c1092 100644 --- a/apps/dafa-web/src/app/pages/call-off/call-off.component.spec.ts +++ b/apps/dafa-web/src/app/pages/avrop/avrop.component.spec.ts @@ -1,22 +1,22 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { CallOffComponent } from './call-off.component'; +import { AvropComponent } from './avrop.component'; describe('CallOffComponent', () => { - let component: CallOffComponent; - let fixture: ComponentFixture; + let component: AvropComponent; + let fixture: ComponentFixture; beforeEach( waitForAsync(() => { TestBed.configureTestingModule({ - declarations: [CallOffComponent], + declarations: [AvropComponent], imports: [RouterTestingModule], }).compileComponents(); }) ); beforeEach(() => { - fixture = TestBed.createComponent(CallOffComponent); + fixture = TestBed.createComponent(AvropComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/apps/dafa-web/src/app/pages/avrop/avrop.component.ts b/apps/dafa-web/src/app/pages/avrop/avrop.component.ts new file mode 100644 index 0000000..2dbe615 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop.component.ts @@ -0,0 +1,67 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { AvropService } from './avrop.service'; +import { Observable } from 'rxjs'; +import { MultiselectFilterOption } from './models/AvropFilterOptions'; +import { Deltagare } from './models/Deltagare'; +import { Handledare } from './models/Handledare'; + +@Component({ + selector: 'dafa-avrop', + templateUrl: './avrop.component.html', + styleUrls: ['./avrop.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AvropComponent implements OnInit { + steps = 3; + + currentStep$ = this.avropService.currentStep$; + + selectedUtforandeVerksamheter$: Observable = this.avropService + .selectedUtforandeVerksamheter$; + selectableDeltagareList$: Observable = this.avropService.selectableDeltagareList$; + selectedDeltagareList$: Observable = this.avropService.selectedDeltagareList$; + deltagareListIsLocked$: Observable = this.avropService.deltagareListIsLocked$; + selectableHandledareList$: Observable = this.avropService.selectableHandledareList$; + selectedHandledare$: Observable = this.avropService.selectedHandledare$; + handledareConfirmed$: Observable = this.avropService.handledareIsConfirmed$; + + constructor(private avropService: AvropService) {} + + updateSelectedDeltagareList(deltagareList: Deltagare[]) { + this.avropService.setSelectedDeltagare(deltagareList); + } + + lockSelectedDeltagare() { + this.avropService.lockSelectedDeltagare(); + } + + unlockSelectedDeltagare() { + this.avropService.unlockSelectedDeltagare(); + } + + ngOnInit(): void { + // this.avropService.loadFromAPI(); + } + + confirmHandledare() { + this.avropService.confirmHandledare(); + } + + unconfirmHandledare() { + this.avropService.unconfirmHandledare(); + } + + save() { + this.avropService.save(); + } + + changeHandledare(newHandledare: Event) { + const handledareId = newHandledare.target['value']; + + this.avropService.setHandledareState(handledareId); + } + + goToStep1() { + this.avropService.goToStep1(); + } +} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop.module.ts b/apps/dafa-web/src/app/pages/avrop/avrop.module.ts new file mode 100644 index 0000000..7e787e8 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop.module.ts @@ -0,0 +1,24 @@ +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 { 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'; + +@NgModule({ + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [AvropComponent, AvropFiltersComponent, AvropTableComponent, AvropTableRowComponent, TemporaryFilterComponent], + imports: [ + CommonModule, + RouterModule.forChild([{ path: '', component: AvropComponent }]), + LoggedInShellModule, + DigiNgProgressProgressbarModule, + DigiNgSkeletonBaseModule, + ], +}) +export class AvropModule {} diff --git a/apps/dafa-web/src/app/pages/avrop/avrop.service.ts b/apps/dafa-web/src/app/pages/avrop/avrop.service.ts new file mode 100644 index 0000000..e4c7a0c --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/avrop.service.ts @@ -0,0 +1,177 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; +import { MultiselectFilterOption } from './models/AvropFilterOptions'; +import { Deltagare } from './models/Deltagare'; +import { Handledare } from './models/Handledare'; +import { first, map, switchMap } from 'rxjs/operators'; +import { AvropApiService } from '@dafa-services/api/avrop-api.service'; + +type Step = 1 | 2 | 3 | 4; + +@Injectable({ + providedIn: 'root', +}) +export class AvropService { + private _selectedTjanster$ = new BehaviorSubject(null); + private _selectedUtforandeVerksamheter$ = new BehaviorSubject(null); + private _selectedKommuner$ = new BehaviorSubject(null); + private _selectedDeltagareList$ = new BehaviorSubject([]); + private _deltagareListIsLocked$ = new BehaviorSubject(null); + private _selectedHandledare$ = new BehaviorSubject(null); + private _handledareIsConfirmed$ = new BehaviorSubject(false); + private _avropIsSaved$ = new BehaviorSubject(false); + + selectedTjanster$: Observable = this._selectedTjanster$.asObservable(); + selectedUtforandeVerksamheter$: Observable< + MultiselectFilterOption[] + > = this._selectedUtforandeVerksamheter$.asObservable(); + selectedKommuner$: Observable = this._selectedKommuner$.asObservable(); + + selectableDeltagareList$: Observable = combineLatest([ + this.selectedTjanster$, + this.selectedUtforandeVerksamheter$, + this.selectedKommuner$, + ]).pipe( + switchMap(([selectedTjanster, selectedUtforandeVerksamheter, selectedKommuner]) => + this.avropApiService.getNyaDeltagare$(selectedTjanster, selectedKommuner, selectedUtforandeVerksamheter) + ) + ); + + selectableTjanster$: Observable = combineLatest([ + this.selectedUtforandeVerksamheter$, + this.selectedKommuner$, + ]).pipe( + switchMap(([selectedUtforandeVerksamheter, selectedKommuner]) => + this.avropApiService.getSelectableTjanster$(selectedKommuner, selectedUtforandeVerksamheter) + ) + ); + selectableUtforandeVerksamheter$: Observable = combineLatest([ + this.selectedTjanster$, + this.selectedKommuner$, + ]).pipe( + switchMap(([selectedTjanster, selectedKommuner]) => + this.avropApiService.getSelectableUtforandeVerksamheter$(selectedTjanster, selectedKommuner) + ) + ); + selectableKommuner$: Observable = combineLatest([ + this.selectedTjanster$, + this.selectedUtforandeVerksamheter$, + ]).pipe( + switchMap(([selectedTjanster, selectedUtforandeVerksamheter]) => + this.avropApiService.getSelectableKommuner$(selectedTjanster, selectedUtforandeVerksamheter) + ) + ); + + selectedDeltagareList$: Observable = this._selectedDeltagareList$.asObservable(); + + deltagareListIsLocked$: Observable = this._deltagareListIsLocked$.asObservable(); + lockedDeltagareList$: Observable = combineLatest([ + this.selectedDeltagareList$, + this.deltagareListIsLocked$, + ]).pipe(map(([selectedDeltagareList, isLocked]) => (isLocked ? selectedDeltagareList : null))); + + selectableHandledareList$: Observable = this.lockedDeltagareList$.pipe( + switchMap(lockedDeltagare => this.avropApiService.getSelectableHandledare$(lockedDeltagare)) + ); + + selectedHandledare$: Observable = this._selectedHandledare$.asObservable(); + + handledareIsConfirmed$: Observable = this._handledareIsConfirmed$.asObservable(); + avropIsSaved$: Observable = this._handledareIsConfirmed$.asObservable(); + + currentStep$: Observable = combineLatest([ + this.handledareIsConfirmed$, + this._deltagareListIsLocked$, + this.avropIsSaved$, + ]).pipe( + map(([confirmedHandledare, lockedDeltagareList, avropIsSaved]) => + AvropService.calculateStep(confirmedHandledare, lockedDeltagareList, avropIsSaved) + ) + ); + + private static calculateStep( + confirmedHandledare: boolean, + deltagareListIsLocked: boolean, + avropIsSaved: boolean + ): Step { + if (avropIsSaved && confirmedHandledare && deltagareListIsLocked) { + return 4; + } + + if (confirmedHandledare && deltagareListIsLocked) { + return 3; + } + + if (deltagareListIsLocked) { + return 2; + } + + return 1; + } + + setSelectedDeltagare(deltagare: Deltagare[]) { + this._selectedDeltagareList$.next(deltagare); + } + + constructor(private avropApiService: AvropApiService) {} + + lockSelectedDeltagare() { + if ((this._selectedDeltagareList$?.value?.length ?? -1) <= 0) { + throw new Error('För att låsa deltagare behöver några ha markerats först.'); + } + this._deltagareListIsLocked$.next(true); + } + + unlockSelectedDeltagare() { + this._deltagareListIsLocked$.next(false); + } + + confirmHandledare() { + if (!this._selectedHandledare$?.value) { + throw new Error('För att kunna tilldela behövs en handledare väljas först.'); + } + this._handledareIsConfirmed$.next(true); + } + + unconfirmHandledare() { + this._handledareIsConfirmed$.next(false); + } + + async save() { + if (!this._handledareIsConfirmed$) { + throw new Error('Handledaren måste bekräftas innan avropet kan sparas'); + } + + if (!this._deltagareListIsLocked$) { + throw new Error('Deltagarlistan måste låsas innan avropet kan sparas'); + } + + await this.avropApiService.tilldelaHandledare(this._selectedDeltagareList$.value, this._selectedHandledare$.value); + this._avropIsSaved$.next(true); + } + + setHandledareState(handledareId: string) { + this.selectableHandledareList$.pipe(first()).subscribe(handledareList => { + this._selectedHandledare$.next(handledareList.find(handledare => handledare.id === handledareId)); + }); + } + + setSelectedTjanster(selectedFilterOptions: MultiselectFilterOption[]) { + this._selectedTjanster$.next(selectedFilterOptions); + } + + setSelectedUtforandeVerksamheter(selectedFilterOptions: MultiselectFilterOption[]) { + this._selectedUtforandeVerksamheter$.next(selectedFilterOptions); + } + + setSelectedKommuner(selectedFilterOptions: MultiselectFilterOption[]) { + this._selectedKommuner$.next(selectedFilterOptions); + } + + goToStep1() { + this._selectedHandledare$.next(null); + this._selectedDeltagareList$.next(null); + this._deltagareListIsLocked$.next(false); + this._handledareIsConfirmed$.next(false); + } +} diff --git a/apps/dafa-web/src/app/pages/avrop/models/AvropFilterOptions.ts b/apps/dafa-web/src/app/pages/avrop/models/AvropFilterOptions.ts new file mode 100644 index 0000000..5ad148a --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/models/AvropFilterOptions.ts @@ -0,0 +1,5 @@ +export interface MultiselectFilterOption { + label: string; + id: string; + count: number; +} diff --git a/apps/dafa-web/src/app/pages/avrop/models/Deltagare.ts b/apps/dafa-web/src/app/pages/avrop/models/Deltagare.ts new file mode 100644 index 0000000..3d8ad53 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/models/Deltagare.ts @@ -0,0 +1,3 @@ +export interface Deltagare { + fullName: string; +} diff --git a/apps/dafa-web/src/app/pages/avrop/models/Handledare.ts b/apps/dafa-web/src/app/pages/avrop/models/Handledare.ts new file mode 100644 index 0000000..4709e93 --- /dev/null +++ b/apps/dafa-web/src/app/pages/avrop/models/Handledare.ts @@ -0,0 +1,4 @@ +export interface Handledare { + fullName: string; + id: string; +} diff --git a/apps/dafa-web/src/app/pages/call-off/call-off.component.html b/apps/dafa-web/src/app/pages/call-off/call-off.component.html deleted file mode 100644 index f1b7f89..0000000 --- a/apps/dafa-web/src/app/pages/call-off/call-off.component.html +++ /dev/null @@ -1 +0,0 @@ -
Avrop funkar!
diff --git a/apps/dafa-web/src/app/pages/call-off/call-off.component.ts b/apps/dafa-web/src/app/pages/call-off/call-off.component.ts deleted file mode 100644 index 5dfebfd..0000000 --- a/apps/dafa-web/src/app/pages/call-off/call-off.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; - -@Component({ - selector: 'dafa-call-off', - templateUrl: './call-off.component.html', - styleUrls: ['./call-off.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class CallOffComponent {} diff --git a/apps/dafa-web/src/app/pages/call-off/call-off.module.ts b/apps/dafa-web/src/app/pages/call-off/call-off.module.ts deleted file mode 100644 index 91e5913..0000000 --- a/apps/dafa-web/src/app/pages/call-off/call-off.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { CallOffComponent } from './call-off.component'; -import { LoggedInShellModule } from '../../components/logged-in-shell/logged-in-shell.module'; - -@NgModule({ - declarations: [CallOffComponent], - imports: [CommonModule, RouterModule.forChild([{ path: '', component: CallOffComponent }]), LoggedInShellModule] -}) -export class CallOffModule {} diff --git a/apps/dafa-web/src/app/pages/ciam-landing/ciam-landing.component.spec.ts b/apps/dafa-web/src/app/pages/ciam-landing/ciam-landing.component.spec.ts deleted file mode 100644 index c96abde..0000000 --- a/apps/dafa-web/src/app/pages/ciam-landing/ciam-landing.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { CiamLandingComponent } from './ciam-landing.component'; - -describe('ReleasesComponent', () => { - let component: CiamLandingComponent; - let fixture: ComponentFixture; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA], - declarations: [CiamLandingComponent], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(CiamLandingComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/dafa-web/src/app/pages/logout/logout.component.spec.ts b/apps/dafa-web/src/app/pages/logout/logout.component.spec.ts deleted file mode 100644 index 0cbe5dc..0000000 --- a/apps/dafa-web/src/app/pages/logout/logout.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { LogoutComponent } from './logout.component'; - -describe('ReleasesComponent', () => { - let component: LogoutComponent; - let fixture: ComponentFixture; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA], - declarations: [LogoutComponent], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(LogoutComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/dafa-web/src/app/pages/participants/pages/participant-card/participant-card.component.spec.ts b/apps/dafa-web/src/app/pages/participants/pages/participant-card/participant-card.component.spec.ts deleted file mode 100644 index 8b3d7f7..0000000 --- a/apps/dafa-web/src/app/pages/participants/pages/participant-card/participant-card.component.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { DigiNgTableModule } from '@af/digi-ng/_table/table'; -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { ParticipantCardComponent } from './participant-card.component'; - -describe('ParticipantCardComponent', () => { - let component: ParticipantCardComponent; - let fixture: ComponentFixture; - - beforeEach(async () => { - await TestBed.configureTestingModule({ - schemas: [CUSTOM_ELEMENTS_SCHEMA], - declarations: [ParticipantCardComponent], - imports: [RouterTestingModule, DigiNgTableModule], - }).compileComponents(); - }); - - beforeEach(() => { - fixture = TestBed.createComponent(ParticipantCardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/apps/dafa-web/src/app/services/api/avrop-api.service.ts b/apps/dafa-web/src/app/services/api/avrop-api.service.ts new file mode 100644 index 0000000..7b6d7a1 --- /dev/null +++ b/apps/dafa-web/src/app/services/api/avrop-api.service.ts @@ -0,0 +1,106 @@ +import { Injectable } from '@angular/core'; +import { Deltagare } from '../../pages/avrop/models/Deltagare'; +import { Handledare } from '../../pages/avrop/models/Handledare'; +import { Observable, of } from 'rxjs'; +import { delay } from 'rxjs/operators'; +import { MultiselectFilterOption } from '../../pages/avrop/models/AvropFilterOptions'; + +const tempHandledareMock: Handledare[] = [ + { id: '1', fullName: 'Göran Persson' }, + { id: '2', fullName: 'Stefan Löfven' }, +]; + +const tempDeltagareMock: Deltagare[] = [{ fullName: 'Daniel' }, { fullName: 'Chingiz' }]; + +const tempKommunerMock: MultiselectFilterOption[] = [ + { id: '124', count: 12, label: 'Stockholm' }, + { id: '125', count: 42, label: 'Göteborg' }, +]; + +const tempUtforandeVerksamheterMock: MultiselectFilterOption[] = [ + { id: 'a124', count: 312, label: 'Utf verk 1' }, + { id: 'b125', count: 142, label: 'Utf verk 2' }, +]; +const tempTjansterMock: MultiselectFilterOption[] = [ + { id: '013', count: 312, label: 'Karriärvägledning' }, + { id: '321', count: 142, label: 'Karriärval rusta och matcha' }, +]; + +@Injectable({ + providedIn: 'root', +}) +export class AvropApiService { + constructor() {} + + getNyaDeltagare$( + tjanstIds: MultiselectFilterOption[], + kommunIds: MultiselectFilterOption[], + utforandeVerksamhetIds: MultiselectFilterOption[] + ): Observable { + // TODO replace with API-call using tjanstIds, kommunIds, utforandeVerksamhetIds + console.log( + '[API call] getNyaDeltagare$. Inputs: tjanstIds, kommunIds, utforandeVerksamhetIds', + tjanstIds, + kommunIds, + utforandeVerksamhetIds + ); + console.log( + '[API call] getNyaDeltagare$. Inputs: tjanstIds, kommunIds, utforandeVerksamhetIds', + tjanstIds, + kommunIds, + utforandeVerksamhetIds + ); + return of(tempDeltagareMock).pipe(delay(300)); + } + + getSelectableHandledare$(deltagare: Deltagare[]): Observable { + // TODO replace with API-call + console.log('[API call] getSelectableHandledare$. Inputs: deltagare', deltagare); + return of(tempHandledareMock).pipe(delay(350)); + } + + getSelectableTjanster$( + selectedKommuner: MultiselectFilterOption[], + selectedUtforandeVerksamheter: MultiselectFilterOption[] + ): Observable { + // TODO replace with API-call + console.log( + '[API call] getSelectableTjanster$. Inputs: selectedKommuner, selectedUtforandeVerksamheter', + selectedKommuner, + selectedUtforandeVerksamheter + ); + return of(tempTjansterMock).pipe(delay(300)); + } + + getSelectableUtforandeVerksamheter$( + selectedTjanster: MultiselectFilterOption[], + selectedKommuner: MultiselectFilterOption[] + ): Observable { + // TODO replace with API-call + console.log( + '[API call] getSelectableUtforandeVerksamheter$. Inputs: selectedTjanster, selectedKommuner', + selectedTjanster, + selectedKommuner + ); + return of(tempUtforandeVerksamheterMock).pipe(delay(300)); + } + + getSelectableKommuner$( + selectedTjanster: MultiselectFilterOption[], + selectedUtforandeVerksamheter: MultiselectFilterOption[] + ): Observable { + // TODO replace with API-call + console.log( + '[API call] getSelectableKommuner$. Inputs: selectedTjanster, selectedUtforandeVerksamheter', + selectedTjanster, + selectedUtforandeVerksamheter + ); + return of(tempKommunerMock).pipe(delay(300)); + } + + async tilldelaHandledare(deltagare: Deltagare[], handledare: Handledare) { + console.log('[API call] SAVE avrop. Inputs: deltagare, handledare', deltagare, handledare); + // TODO anropa API + return; + } +} diff --git a/mock-api/dafa-web/scripts/avrop.js b/mock-api/dafa-web/scripts/avrop.js index d28650c..0dbc516 100644 --- a/mock-api/dafa-web/scripts/avrop.js +++ b/mock-api/dafa-web/scripts/avrop.js @@ -26,7 +26,6 @@ function generateIncomingAvrop(amount = 10) { errandNumber: faker.datatype.number({ min: 100000, max: 999999 }), startDate: faker.date.recent(), endDate: faker.date.future(), - //handleBefore: faker.date.soon(), supportLanguage: language.name, interpreter: language.name, organization: ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)], @@ -35,7 +34,7 @@ function generateIncomingAvrop(amount = 10) { avropList.push({ ...avrop, fullName: `${avrop.firstName} ${avrop.lastName}` }); } - console.info('Incoming avrop generated...', avropList); + console.info('Incoming avrop generated...'); return avropList; }