diff --git a/apps/mina-sidor-fa/src/app/pages/administration/pages/employee-form/edit-employee-form/edit-employee-form.component.ts b/apps/mina-sidor-fa/src/app/pages/administration/pages/employee-form/edit-employee-form/edit-employee-form.component.ts
index 0b39552..849270d 100644
--- a/apps/mina-sidor-fa/src/app/pages/administration/pages/employee-form/edit-employee-form/edit-employee-form.component.ts
+++ b/apps/mina-sidor-fa/src/app/pages/administration/pages/employee-form/edit-employee-form/edit-employee-form.component.ts
@@ -23,10 +23,10 @@ import { UtforandeVerksamhet } from '@msfa-models/utforande-verksamhet.model';
import { UtforandeVerksamheterService } from '@msfa-services/utforande-verksamheter/utforande-verksamheter.service';
import { ValidationErrorLink } from '@msfa-shared/components/error-list/error-list.component';
import { TreeNodesSelectorService } from '@msfa-shared/components/tree-nodes-selector/services/tree-nodes-selector.service';
+import { uuid } from '@msfa-utils/uuid';
import { EmailValidator } from '@msfa-utils/validators/email.validator';
import { EmployeeValidator } from '@msfa-utils/validators/employee.validator';
import { RequiredValidator } from '@msfa-utils/validators/required.validator';
-import { UUID } from 'angular2-uuid';
import { EmployeeFormService } from '../services/employee-form.service';
@Component({
@@ -58,7 +58,7 @@ export class EditEmployeeFormComponent implements OnInit, OnChanges {
readonly utforandeVerksamheterFormControlName = 'utforandeVerksamheter';
readonly selectAllUtforandeVerksamheterFormControlName = 'allaUtforandeVerksamheter';
readonly utforandeVerksamhetRequiredMessage = 'Välj minst en utförande verksamhet';
- readonly formUuid = UUID.UUID();
+ readonly formUuid = uuid();
readonly emailElementId = `email-control-${this.formUuid}`;
readonly tjansterElementId = `tjanster-control-${this.formUuid}`;
readonly utforandeVerksamhetElementId = `utforande-verksamhet-control-${this.formUuid}`;
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.ts b/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.ts
index d0de1b6..8f2e203 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.ts
+++ b/apps/mina-sidor-fa/src/app/pages/avrop/avrop.component.ts
@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Avrop, AvropCompactData } from '@msfa-models/avrop.model';
import { Handledare } from '@msfa-models/handledare.model';
-import { MultiselectFilterOption } from '@msfa-models/multiselect-filter-option';
+import { MultiselectFilterOption } from '@msfa-shared/components/multiselect/multiselect-filter-option';
import { AvropService } from '@msfa-services/avrop.service';
import { Observable } from 'rxjs';
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.html b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.html
index 28aa86a..4ff7d8d 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.html
+++ b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.html
@@ -1,29 +1,32 @@
-
-
-
+
+
-
-
-
+
+
+
-
+ >
+
-
-
+
-
+ >
+
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.scss b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.scss
index 9a4dfac..127a121 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.scss
+++ b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.scss
@@ -1,6 +1,8 @@
@import 'variables/gutters';
.avrop-filters {
+ display: flex;
+
&__tags {
display: flex;
flex-wrap: wrap;
@@ -9,9 +11,13 @@
&__tag {
display: inline-block;
- margin-right: $digi--layout--gutter--s;
+ margin-right: var(--digi--layout--gutter--s);
}
&__loading-spinner {
- margin-right: $digi--layout--gutter;
+ margin-right: var(--digi--layout--gutter);
+ }
+
+ &__filter-wrapper {
+ margin-right: var(--digi--layout--gutter--s);
}
}
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.spec.ts b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.spec.ts
index 929f5e3..387cc97 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.spec.ts
+++ b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.spec.ts
@@ -4,7 +4,6 @@ import { ComponentFixture, discardPeriodicTasks, fakeAsync, TestBed, tick } from
import { By } from '@angular/platform-browser';
import { AvropService } from '@msfa-services/avrop.service';
import { of } from 'rxjs';
-import { TemporaryFilterComponent } from '../temporary-filter/temporary-filter.component';
import { AvropFiltersComponent } from './avrop-filters.component';
describe('AvropFiltersComponent', () => {
@@ -15,7 +14,7 @@ describe('AvropFiltersComponent', () => {
await TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [HttpClientTestingModule],
- declarations: [AvropFiltersComponent, TemporaryFilterComponent],
+ declarations: [AvropFiltersComponent],
providers: [AvropService],
}).compileComponents();
});
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.ts b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.ts
index 970c57c..dd7755b 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.ts
+++ b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.component.ts
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { MultiselectFilterOption } from '@msfa-models/multiselect-filter-option';
+import { MultiselectFilterOption } from '@msfa-shared/components/multiselect/multiselect-filter-option';
import { AvropService } from '@msfa-services/avrop.service';
import { Observable } from 'rxjs';
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.module.ts b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.module.ts
index 9009134..c76d143 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.module.ts
+++ b/apps/mina-sidor-fa/src/app/pages/avrop/components/avrop-filters/avrop-filters.module.ts
@@ -1,12 +1,12 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
-import { TemporaryFilterModule } from '../temporary-filter/temporary-filter.module';
import { AvropFiltersComponent } from './avrop-filters.component';
+import { MultiselectModule } from '@msfa-shared/components/multiselect/multiselect.module';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [AvropFiltersComponent],
- imports: [CommonModule, TemporaryFilterModule],
+ imports: [CommonModule, MultiselectModule],
exports: [AvropFiltersComponent],
})
export class AvropFiltersModule {}
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.html b/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.html
deleted file mode 100644
index e115483..0000000
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
- {{filterLabel}}
-
-
-
- Spara
-
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.scss b/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.scss
deleted file mode 100644
index e69de29..0000000
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.ts b/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.ts
deleted file mode 100644
index eebdbe5..0000000
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import {
- ChangeDetectionStrategy,
- Component,
- EventEmitter,
- Input,
- OnChanges,
- OnInit,
- Output,
- SimpleChanges,
-} from '@angular/core';
-import { MultiselectFilterOption } from '@msfa-models/multiselect-filter-option';
-import { BehaviorSubject, Observable } from 'rxjs';
-
-@Component({
- selector: 'msfa-temporary-filter',
- templateUrl: './temporary-filter.component.html',
- styleUrls: ['./temporary-filter.component.scss'],
- changeDetection: ChangeDetectionStrategy.OnPush,
-})
-export class TemporaryFilterComponent implements OnInit, OnChanges {
- private _selectedAvropFilterOption$ = new BehaviorSubject
(null);
- selectedAvropFilterOptionState$: Observable;
-
- @Input() filterLabel: string;
- @Input() filterOptions: MultiselectFilterOption[];
- @Input() selectedOptions: MultiselectFilterOption[];
- @Output() selectedOptionsChange = new EventEmitter();
-
- // THIS SHOULD BE REPLACED BY DIGI COMPONENT
- ngOnInit(): void {
- this._selectedAvropFilterOption$ = new BehaviorSubject(this.selectedOptions);
- this.selectedAvropFilterOptionState$ = this._selectedAvropFilterOption$.asObservable();
- }
-
- ngOnChanges(changes: SimpleChanges): void {
- if (changes.selectedOptions?.currentValue) {
- this._selectedAvropFilterOption$.next(changes.selectedOptions.currentValue);
- }
- }
-
- isSelected(filterOption: MultiselectFilterOption): boolean {
- return this.selectedOptions?.includes(filterOption) ?? false;
- }
-
- setOptionState(filterOption: MultiselectFilterOption, isSelected: boolean): void {
- if (isSelected) {
- return this._selectedAvropFilterOption$.next([...(this._selectedAvropFilterOption$.value ?? []), filterOption]);
- }
- return this._selectedAvropFilterOption$.next(
- this._selectedAvropFilterOption$.value?.filter(item => item != filterOption) ?? []
- );
- }
-
- emitSelectedOptions(): void {
- this.selectedOptionsChange.emit(this._selectedAvropFilterOption$.value);
- }
-}
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.module.ts b/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.module.ts
deleted file mode 100644
index 3f1e70a..0000000
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.module.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { CommonModule } from '@angular/common';
-import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
-import { TemporaryFilterComponent } from './temporary-filter.component';
-
-@NgModule({
- schemas: [CUSTOM_ELEMENTS_SCHEMA],
- declarations: [TemporaryFilterComponent],
- imports: [CommonModule],
- exports: [TemporaryFilterComponent],
-})
-export class TemporaryFilterModule {}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown-panel.ts b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown-panel.ts
new file mode 100644
index 0000000..dcbfbb5
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown-panel.ts
@@ -0,0 +1,6 @@
+import { EventEmitter, TemplateRef } from '@angular/core';
+
+export interface DropdownPanel {
+ templateRef: TemplateRef;
+ readonly closed: EventEmitter;
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown-trigger-for.directive.ts b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown-trigger-for.directive.ts
new file mode 100644
index 0000000..69edae3
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown-trigger-for.directive.ts
@@ -0,0 +1,101 @@
+import { Overlay, OverlayRef } from '@angular/cdk/overlay';
+import { TemplatePortal } from '@angular/cdk/portal';
+import { Directive, ElementRef, HostListener, Input, OnDestroy, ViewContainerRef } from '@angular/core';
+import { merge, Observable, Subscription } from 'rxjs';
+import { DropdownPanel } from './dropdown-panel';
+
+@Directive({
+ selector: '[msfaDropdownTriggerFor]',
+})
+export class DropdownTriggerForDirective implements OnDestroy {
+ @Input('msfaDropdownTriggerFor') public dropdownPanel: DropdownPanel;
+
+ private isDropdownOpen = false;
+ public overlayRef: OverlayRef;
+ private dropdownClosingActionsSub = Subscription.EMPTY;
+
+ private onClosedCallback: () => void = () => {
+ return;
+ };
+ private onOpenCallback: () => void = () => {
+ return;
+ };
+
+ @HostListener('click') onClick(): void {
+ return this.toggleDropdown();
+ }
+ @HostListener('document:keyup.escape', ['$event']) onKeydownHandler(): void {
+ this.closeDropdown();
+ }
+
+ constructor(
+ private overlay: Overlay,
+ private elementRef: ElementRef,
+ private viewContainerRef: ViewContainerRef
+ ) {}
+
+ toggleDropdown(): void {
+ this.isDropdownOpen ? this.closeDropdown() : this.openDropdown();
+ }
+
+ openDropdown(): void {
+ this.isDropdownOpen = true;
+ this.overlayRef = this.overlay.create({
+ hasBackdrop: true,
+ backdropClass: 'cdk-overlay-transparent-backdrop',
+ scrollStrategy: this.overlay.scrollStrategies.close(),
+ positionStrategy: this.overlay
+ .position()
+ .flexibleConnectedTo(this.elementRef)
+ .withPositions([
+ {
+ originX: 'start',
+ originY: 'bottom',
+ overlayX: 'start',
+ overlayY: 'top',
+ offsetY: 3,
+ },
+ ]),
+ });
+
+ const templatePortal = new TemplatePortal(this.dropdownPanel.templateRef, this.viewContainerRef);
+
+ this.overlayRef.attach(templatePortal);
+ this.onOpenCallback();
+
+ this.dropdownClosingActionsSub = this.dropdownClosingActions().subscribe(() => this.closeDropdown());
+ }
+
+ private dropdownClosingActions(): Observable {
+ const backdropClick$ = this.overlayRef.backdropClick();
+ const detachment$ = this.overlayRef.detachments();
+ const dropdownClosed = this.dropdownPanel.closed;
+
+ return merge(backdropClick$, detachment$, dropdownClosed);
+ }
+
+ closeDropdown(): void {
+ if (!this.overlayRef || !this.isDropdownOpen) {
+ return;
+ }
+
+ this.onClosedCallback();
+ this.dropdownClosingActionsSub.unsubscribe();
+ this.isDropdownOpen = false;
+ this.overlayRef.detach();
+ }
+
+ ngOnDestroy(): void {
+ if (this.overlayRef) {
+ this.overlayRef.dispose();
+ }
+ }
+
+ onClosed(fn: () => void): void {
+ this.onClosedCallback = fn;
+ }
+
+ onOpen(fn: () => void): void {
+ this.onOpenCallback = fn;
+ }
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.html b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.html
new file mode 100644
index 0000000..4c65e10
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.html
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.scss b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.scss
new file mode 100644
index 0000000..c0e699d
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.scss
@@ -0,0 +1,7 @@
+@import "variables/shadows";
+
+.dropdown-content {
+ background-color: white;
+ border-radius: var(--digi--ui--border--radius);
+ box-shadow: $msfa__shadow;
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.spec.ts b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.spec.ts
new file mode 100644
index 0000000..8fde5e0
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DropdownComponent } from './dropdown.component';
+
+describe('DropdownComponent', () => {
+ let component: DropdownComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ DropdownComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DropdownComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.ts b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.ts
new file mode 100644
index 0000000..562e4e4
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.component.ts
@@ -0,0 +1,13 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Output, TemplateRef, ViewChild } from '@angular/core';
+import { DropdownPanel } from './dropdown-panel';
+
+@Component({
+ selector: 'msfa-dropdown',
+ templateUrl: './dropdown.component.html',
+ styleUrls: ['./dropdown.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DropdownComponent implements DropdownPanel {
+ @ViewChild(TemplateRef) templateRef: TemplateRef;
+ @Output() closed = new EventEmitter();
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.module.ts b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.module.ts
new file mode 100644
index 0000000..ecd2958
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/dropdown/dropdown.module.ts
@@ -0,0 +1,13 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { DropdownTriggerForDirective } from './dropdown-trigger-for.directive';
+import { DropdownComponent } from './dropdown.component';
+import { OverlayModule } from '@angular/cdk/overlay';
+import { A11yModule } from '@angular/cdk/a11y';
+
+@NgModule({
+ declarations: [DropdownTriggerForDirective, DropdownComponent],
+ imports: [CommonModule, OverlayModule, A11yModule],
+ exports: [DropdownTriggerForDirective, DropdownComponent],
+})
+export class DropdownModule {}
diff --git a/apps/mina-sidor-fa/src/app/shared/models/multiselect-filter-option.ts b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-filter-option.ts
similarity index 80%
rename from apps/mina-sidor-fa/src/app/shared/models/multiselect-filter-option.ts
rename to apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-filter-option.ts
index e315282..40e7fea 100644
--- a/apps/mina-sidor-fa/src/app/shared/models/multiselect-filter-option.ts
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-filter-option.ts
@@ -2,4 +2,5 @@ export interface MultiselectFilterOption {
label?: string;
id?: string;
count?: number;
+ secondary?: boolean;
}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.html b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.html
new file mode 100644
index 0000000..23becb1
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.html
@@ -0,0 +1,60 @@
+
+
+
+
+
+ I kombination med dina nuvarande filterval, finns det inga nya deltagare med {{ multiselectTitlePlural }} att
+ filtrera på.
+
+
+
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.scss b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.scss
new file mode 100644
index 0000000..db6904d
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.scss
@@ -0,0 +1,115 @@
+@import 'mixins/form';
+
+@import 'mixins/a11y';
+.multiselect-panel {
+ &__checkboxes {
+ max-width: var(--digi--typography--text--max-width);
+ padding: var(--digi--layout--padding--15);
+ }
+
+ &__fieldset {
+ @include msfa__fieldset;
+ }
+
+ &__checkboxes-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ &__checkboxes-item {
+ margin-top: var(--digi--layout--gutter--s);
+
+ &:first-child {
+ margin-top: 0;
+ }
+
+ &--unavailable {
+ margin-top: var(--digi--layout--gutter);
+ }
+ }
+
+ &__search-wrapper {
+ position: relative;
+ margin-bottom: var(--digi--layout--gutter--l);
+
+ &--searched {
+ margin-bottom: var(--digi--layout--gutter--s);
+ }
+ }
+
+ &__select-all {
+ margin-bottom: var(--digi--layout--gutter--l);
+ }
+
+ &__search-input ::ng-deep .digi-ng-form-input__label {
+ @include msfa__a11y-sr-only;
+ }
+
+ &__input-reset-button {
+ position: absolute;
+ right: 0;
+ top: 1px;
+ }
+}
+
+.multiselect-panel {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+
+ ::ng-deep &__backdrop {
+ background-color: rgba(var(--digi--ui--color--background--dark), 40%);
+ }
+
+ &__fieldset {
+ margin: 0;
+ padding: 0;
+ border-width: 0;
+ }
+
+ &__legend {
+ position: relative;
+ text-align: left;
+ }
+
+ &__heading,
+ &__legend {
+ width: 100%;
+ height: 45px;
+ display: flex;
+ align-items: center;
+ margin: 0;
+ font-weight: var(--digi--typography--font-weight--bold);
+ font-size: var(--digi--typography--font-size);
+ padding: var(--digi--layout--gutter--s) var(--digi--layout--gutter);
+ border-bottom: 1px solid var(--digi--ui--color--background--tertiary);
+ }
+
+ &__content {
+ position: relative;
+ flex-grow: 1;
+ }
+
+ &__inner-content {
+ width: 100%;
+ min-width: 300px;
+ max-width: 800px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ }
+
+ &__footer {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: var(--digi--ui--color--background--tertiary);
+ height: 70px;
+ }
+
+ &__no-options-available {
+ text-align: center;
+ padding: var(--digi--layout--gutter--s);
+ max-width: 300px;
+ }
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.spec.ts b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.spec.ts
new file mode 100644
index 0000000..4149d1f
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.spec.ts
@@ -0,0 +1,25 @@
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MultiselectPanelComponent } from './multiselect-panel.component';
+
+describe('MultiselectPanelComponent', () => {
+ let component: MultiselectPanelComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [MultiselectPanelComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MultiselectPanelComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.ts b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.ts
new file mode 100644
index 0000000..839626f
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect-panel/multiselect-panel.component.ts
@@ -0,0 +1,71 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ EventEmitter,
+ Input,
+ OnChanges,
+ Output,
+ SimpleChanges,
+} from '@angular/core';
+import { DropdownTriggerForDirective } from '@msfa-shared/components/dropdown/dropdown-trigger-for.directive';
+import { MultiselectFilterOption } from '@msfa-shared/components/multiselect/multiselect-filter-option';
+import { BehaviorSubject } from 'rxjs';
+
+@Component({
+ selector: 'msfa-multiselect-panel',
+ templateUrl: './multiselect-panel.component.html',
+ styleUrls: ['./multiselect-panel.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class MultiselectPanelComponent implements OnChanges {
+ @Input() dropdownRef: DropdownTriggerForDirective;
+ @Input() confirmButtonText = 'Spara';
+ @Input() multiselectTitle: string;
+ @Input() multiselectTitlePlural: string;
+ @Input() description: string;
+ @Input() availableOptions: MultiselectFilterOption[];
+ @Input() selectedOptions: MultiselectFilterOption[];
+ @Output() selectedOptionsChange = new EventEmitter();
+
+ private _pendingSelectedOptions$ = new BehaviorSubject([]);
+ private _selectedUnavailableOptions$ = new BehaviorSubject([]);
+
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.availableOptions || changes.selectedOptions) {
+ this._setPendingSelectedOptions();
+ }
+ }
+ get selectedUnavailableOptions(): MultiselectFilterOption[] {
+ return this._selectedUnavailableOptions$.getValue();
+ }
+ private get _pendingSelectedOptions(): MultiselectFilterOption[] {
+ return this._pendingSelectedOptions$.getValue();
+ }
+
+ private _setPendingSelectedOptions(): void {
+ this._pendingSelectedOptions$.next(this.selectedOptions || []);
+ this._selectedUnavailableOptions$.next(
+ this.selectedOptions?.filter(
+ selectedOption => !this.availableOptions.some(availableOption => availableOption.id === selectedOption.id)
+ ) || []
+ );
+ }
+
+ isSelected(filterOption: MultiselectFilterOption): boolean {
+ return this._pendingSelectedOptions$.value?.some(selectedOption => selectedOption.id === filterOption.id) ?? false;
+ }
+
+ emitSelectedOptions(): void {
+ this.selectedOptionsChange.emit(this._pendingSelectedOptions);
+ }
+
+ setOptionState(filterOption: MultiselectFilterOption, isSelected: boolean): void {
+ if (isSelected) {
+ this._pendingSelectedOptions$.next([...this._pendingSelectedOptions, filterOption]);
+ } else {
+ this._pendingSelectedOptions$.next(
+ this._pendingSelectedOptions.filter(item => item.id !== filterOption.id) ?? []
+ );
+ }
+ }
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.html b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.html
new file mode 100644
index 0000000..b2add69
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.scss b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.scss
new file mode 100644
index 0000000..c94b9b5
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.scss
@@ -0,0 +1,64 @@
+@import 'variables/colors';
+@import 'mixins/list';
+@import 'variables/gutters';
+
+
+.multiselect {
+
+ &__toggle-btn {
+ margin-right: var(--digi--layout--gutter);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ appearance: none;
+ width: 100%;
+ height: var(--digi--ui--input--height);
+ padding: var(--digi--ui--input--padding);
+ border: 1px solid var(--digi--ui--input--border--color);
+ cursor: pointer;
+ font-size: var(--digi--typography--font-size--m);
+ color: var(--digi--ui--color--background--overlay--opaque);
+ background-color: var(--digi--ui--color--background);
+ border-color: var(--digi-form-select--border-color);
+
+ &:focus {
+ border-color: var(--digi--ui--color--focus--light);
+ box-shadow: 0 0 0.1rem 0.05rem var(--digi--ui--color--focus);
+ outline: none;
+ }
+
+ &:disabled {
+ cursor: default;
+ background-color: var(--digi--ui--color--background--disabled);
+ border-color: var(--digi--ui--color--border--disabled);
+ color: var(--digi--typography--color--text--disabled);
+ }
+
+ &--invalid {
+ background-color: var(--digi--ui--color--background--error);
+ border-color: var(--digi--ui--color--border--error);
+ box-shadow: 0 0 0 1px var(--digi--ui--color--border--error);
+ }
+
+ &__text {
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ }
+
+ &__toggle-btn__arrow-down {
+ padding: var(--digi--layout--padding);
+ }
+
+ &__validation-messages {
+ @include msfa__reset-list;
+ display: flex;
+ justify-content: space-between;
+ padding: var(--digi--layout--gutter--s) 0;
+ flex-direction: column;
+ gap: var(--digi--layout--gutter--s);
+ }
+
+}
diff --git a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.spec.ts b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.spec.ts
similarity index 57%
rename from apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.spec.ts
rename to apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.spec.ts
index 4f3e955..cf12f8e 100644
--- a/apps/mina-sidor-fa/src/app/pages/avrop/components/temporary-filter/temporary-filter.component.spec.ts
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.spec.ts
@@ -1,21 +1,20 @@
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { MultiselectComponent } from './multiselect.component';
-import { TemporaryFilterComponent } from './temporary-filter.component';
-
-describe('TemporaryFilterComponent', () => {
- let component: TemporaryFilterComponent;
- let fixture: ComponentFixture;
+describe('MultiselectComponent', () => {
+ let component: MultiselectComponent;
+ let fixture: ComponentFixture;
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [TemporaryFilterComponent],
+ declarations: [MultiselectComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
}).compileComponents();
});
beforeEach(() => {
- fixture = TestBed.createComponent(TemporaryFilterComponent);
+ fixture = TestBed.createComponent(MultiselectComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.ts b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.ts
new file mode 100644
index 0000000..31ce949
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.component.ts
@@ -0,0 +1,102 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ ElementRef,
+ EventEmitter,
+ forwardRef,
+ Input,
+ AfterViewInit,
+ Output,
+ Renderer2,
+ ViewChild,
+ ChangeDetectorRef,
+} from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { DropdownTriggerForDirective } from '@msfa-shared/components/dropdown/dropdown-trigger-for.directive';
+import { MultiselectFilterOption } from '@msfa-shared/components/multiselect/multiselect-filter-option';
+import { uuid } from '@msfa-utils/uuid';
+
+interface PropagateChangeFn {
+ (_: unknown): void;
+}
+
+interface PropagateTouchedFn {
+ (): void;
+}
+
+@Component({
+ selector: 'msfa-multiselect',
+ templateUrl: './multiselect.component.html',
+ styleUrls: ['./multiselect.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ providers: [
+ {
+ provide: NG_VALUE_ACCESSOR,
+ useExisting: forwardRef(() => MultiselectComponent),
+ multi: true,
+ },
+ ],
+})
+export class MultiselectComponent implements AfterViewInit, ControlValueAccessor {
+ @ViewChild(DropdownTriggerForDirective) dropdownRef: DropdownTriggerForDirective;
+ panelId = `panel-${uuid()}`;
+ @Input() buttonElementId: string = uuid();
+ @Input() isInvalid = false;
+ @Input() showValidation = false;
+ @Input() confirmButtonText = 'Spara';
+ @Input() description: string;
+ @Input() multiselectTitle: string;
+ @Input() availableOptions: MultiselectFilterOption[];
+ @Input() selectedOptions: MultiselectFilterOption[];
+ @Output() selectedOptionsChange = new EventEmitter();
+ @ViewChild('multiselectButton') multiselectButton: ElementRef;
+ isDisabled = false;
+
+ private propagateChange: PropagateChangeFn;
+ private propagateTouched: PropagateTouchedFn;
+
+ constructor(private renderer: Renderer2, private changeDetectionRef: ChangeDetectorRef) {}
+
+ // Allows Angular to update the model.
+ // Update the model and changes needed for the view here.
+ writeValue(selectedOptions: MultiselectFilterOption[]): void {
+ this.selectedOptions = selectedOptions;
+ }
+
+ // Allows Angular to register a function to call when the model changes.
+ // Save the function as a property to call later here.
+ registerOnChange(fn: PropagateChangeFn): void {
+ this.propagateChange = fn;
+ }
+
+ // Allows Angular to register a function to call when the input has been touched.
+ // Save the function as a property to call later here.
+ registerOnTouched(fn: PropagateTouchedFn): void {
+ this.propagateTouched = fn;
+ }
+
+ // Allows Angular to disable the input.
+ setDisabledState?(isDisabled: boolean): void {
+ this.renderer.setProperty(this.multiselectButton.nativeElement, 'disabled', isDisabled);
+ this.dropdownRef.closeDropdown();
+ }
+
+ emitSelectedOptions(selectedOptions: MultiselectFilterOption[]): void {
+ // If used with FormsModule/ReactiveFormsModule
+ if (this.propagateChange && this.propagateTouched) {
+ this.propagateChange(selectedOptions);
+ this.propagateTouched();
+ } else {
+ this.selectedOptionsChange.emit(selectedOptions);
+ }
+
+ this.dropdownRef.closeDropdown();
+ }
+
+ ngAfterViewInit(): void {
+ this.dropdownRef.onOpen(() => {
+ // force refresh of selected options if it's reopened
+ this.selectedOptions = [...(this.selectedOptions || [])];
+ });
+ }
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.module.ts b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.module.ts
new file mode 100644
index 0000000..df03ea5
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/components/multiselect/multiselect.module.ts
@@ -0,0 +1,16 @@
+import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
+import { A11yModule } from '@angular/cdk/a11y';
+import { CommonModule } from '@angular/common';
+import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { DropdownModule } from '@msfa-shared/components/dropdown/dropdown.module';
+import { MultiselectComponent } from '@msfa-shared/components/multiselect/multiselect.component';
+import { MultiselectPanelComponent } from './multiselect-panel/multiselect-panel.component';
+
+@NgModule({
+ declarations: [MultiselectComponent, MultiselectPanelComponent],
+ imports: [CommonModule, DropdownModule, A11yModule, DigiNgFormCheckboxModule, FormsModule],
+ exports: [MultiselectComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+})
+export class MultiselectModule {}
diff --git a/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/expanded-tree-node/expanded-tree-node.component.spec.ts b/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/expanded-tree-node/expanded-tree-node.component.spec.ts
index 0940ffb..91449cd 100644
--- a/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/expanded-tree-node/expanded-tree-node.component.spec.ts
+++ b/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/expanded-tree-node/expanded-tree-node.component.spec.ts
@@ -1,5 +1,5 @@
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
-
import { ExpandedTreeNodeComponent } from './expanded-tree-node.component';
describe('ExpandedTreeNodeComponent', () => {
@@ -8,9 +8,9 @@ describe('ExpandedTreeNodeComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
- declarations: [ ExpandedTreeNodeComponent ]
- })
- .compileComponents();
+ declarations: [ExpandedTreeNodeComponent],
+ schemas: [CUSTOM_ELEMENTS_SCHEMA],
+ }).compileComponents();
});
beforeEach(() => {
diff --git a/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/tree-nodes-selector/tree-nodes-selector.component.ts b/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/tree-nodes-selector/tree-nodes-selector.component.ts
index 2470465..87d9d22 100644
--- a/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/tree-nodes-selector/tree-nodes-selector.component.ts
+++ b/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/components/tree-nodes-selector/tree-nodes-selector.component.ts
@@ -11,7 +11,7 @@ import {
ViewChild,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
-import { UUID } from 'angular2-uuid';
+import { uuid } from '@msfa-utils/uuid';
import { TreeNode, TreeNodeModel, TreeNodesSelectorService } from '../../services/tree-nodes-selector.service';
interface PropagateChangeFn {
@@ -36,7 +36,7 @@ interface PropagateTouchedFn {
],
})
export class TreeNodesSelectorComponent implements ControlValueAccessor {
- @Input() buttonElementId: string = UUID.UUID();
+ @Input() buttonElementId: string = uuid();
@Input() headingText: string;
@Input() confirmationButtonText = 'Spara';
@Input() isInvalid = false;
@@ -51,7 +51,7 @@ export class TreeNodesSelectorComponent implements ControlValueAccessor {
selectionLabel: string | null = null;
isDisabled = false;
- panelId = `panel-${UUID.UUID()}`;
+ panelId = `panel-${uuid()}`;
private propagateChange: PropagateChangeFn;
private propagateTouched: PropagateTouchedFn;
diff --git a/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/services/tree-nodes-selector.service.ts b/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/services/tree-nodes-selector.service.ts
index 499b918..a093412 100644
--- a/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/services/tree-nodes-selector.service.ts
+++ b/apps/mina-sidor-fa/src/app/shared/components/tree-nodes-selector/services/tree-nodes-selector.service.ts
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
-import { UUID } from 'angular2-uuid';
+import { uuid } from '@msfa-utils/uuid';
export interface TreeNode {
label: string;
@@ -43,7 +43,7 @@ export class TreeNodesSelectorService {
return {
...treeNode,
- uuid: UUID.UUID(),
+ uuid: uuid(),
hasFocus: false,
children,
hideTreeNode: false,
diff --git a/apps/mina-sidor-fa/src/app/shared/directives/autofocus/autofocus.directive.ts b/apps/mina-sidor-fa/src/app/shared/directives/autofocus/autofocus.directive.ts
new file mode 100644
index 0000000..0cc1932
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/directives/autofocus/autofocus.directive.ts
@@ -0,0 +1,16 @@
+import { AfterViewInit, Directive, ElementRef, Input } from '@angular/core';
+
+@Directive({
+ selector: '[msfaAutofocus]',
+})
+export class AutofocusDirective implements AfterViewInit {
+ @Input() msfaAutofocus: boolean;
+
+ constructor(private elementRef: ElementRef) {}
+
+ ngAfterViewInit(): void {
+ if (this.msfaAutofocus) {
+ (this.elementRef.nativeElement as HTMLElement).focus();
+ }
+ }
+}
diff --git a/apps/mina-sidor-fa/src/app/shared/directives/autofocus/autofocus.module.ts b/apps/mina-sidor-fa/src/app/shared/directives/autofocus/autofocus.module.ts
new file mode 100644
index 0000000..82aa0cb
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/directives/autofocus/autofocus.module.ts
@@ -0,0 +1,10 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { AutofocusDirective } from './autofocus.directive';
+
+@NgModule({
+ declarations: [AutofocusDirective],
+ imports: [CommonModule],
+ exports: [AutofocusDirective],
+})
+export class AutofocusModule {}
diff --git a/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts b/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts
index a8c0887..ba8c669 100644
--- a/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts
+++ b/apps/mina-sidor-fa/src/app/shared/services/avrop.service.ts
@@ -2,8 +2,8 @@ import { Injectable } from '@angular/core';
import { Params } from '@msfa-models/api/params.model';
import { Avrop, AvropCompactData } from '@msfa-models/avrop.model';
import { Handledare } from '@msfa-models/handledare.model';
-import { MultiselectFilterOption } from '@msfa-models/multiselect-filter-option';
import { AvropApiService } from '@msfa-services/api/avrop-api.service';
+import { MultiselectFilterOption } from '@msfa-shared/components/multiselect/multiselect-filter-option';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { filter, map, switchMap } from 'rxjs/operators';
@@ -50,24 +50,24 @@ export class AvropService {
this._filteredKommuner$,
this._page$,
this._limit$,
- ]).pipe(switchMap(() => this.avropApiService.fetchAvrop$(this._getParams('avrop'))));
+ ]).pipe(switchMap(() => this.avropApiService.fetchAvrop$(this.filtersForAvrop)));
public availableTjanster$: Observable = combineLatest([
this._filteredUtforandeVerksamheter$,
this._filteredKommuner$,
- ]).pipe(switchMap(() => this.avropApiService.fetchAvailableTjanster$(this._getParams('tjanster'))));
+ ]).pipe(switchMap(() => this.avropApiService.fetchAvailableTjanster$(this.filtersForTjanster)));
public availableUtforandeVerksamheter$: Observable = combineLatest([
this._filteredTjanster$,
this._filteredKommuner$,
]).pipe(
- switchMap(() => this.avropApiService.fetchAvailableUtforandeVerksamheter$(this._getParams('utforandeVerksamheter')))
+ switchMap(() => this.avropApiService.fetchAvailableUtforandeVerksamheter$(this.filtersForUtforandeVerksamheter))
);
public availableKommuner$: Observable = combineLatest([
this._filteredTjanster$,
this._filteredUtforandeVerksamheter$,
- ]).pipe(switchMap(() => this.avropApiService.fetchAvailableKommuner$(this._getParams('kommuner'))));
+ ]).pipe(switchMap(() => this.avropApiService.fetchAvailableKommuner$(this.filtersForKommuner)));
private _lockedAvrop$: Observable = combineLatest([this.selectedAvrop$, this.avropIsLocked$]).pipe(
map(([selectedAvrop, isLocked]) => (isLocked ? selectedAvrop : null))
@@ -102,48 +102,57 @@ export class AvropService {
return 1;
}
- private _getParams(type: 'avrop' | 'kommuner' | 'tjanster' | 'utforandeVerksamheter'): Params {
- const tjanstKoder = this._filteredTjanster$.getValue()?.length
- ? { tjanstKoder: this._filteredTjanster$.getValue().map(tjanst => tjanst.id) }
+ private get tjanstKoder(): { tjanstKoder: string[] } | null {
+ return this._filteredTjanster$.value?.length
+ ? { tjanstKoder: this._filteredTjanster$.value.map(tjanst => tjanst.id) }
: null;
- const kommunKoder = this._filteredKommuner$.getValue()?.length
- ? { kommunKoder: this._filteredKommuner$.getValue().map(kommun => kommun.id) }
+ }
+
+ private get kommunKoder(): { kommunKoder: string[] } | null {
+ return this._filteredKommuner$.value?.length
+ ? { kommunKoder: this._filteredKommuner$.value.map(kommun => kommun.id) }
: null;
- const utforandeverksamhetIds = this._filteredUtforandeVerksamheter$.getValue()?.length
+ }
+
+ private get utforandeverksamhetIds(): { utforandeverksamhetIds: string[] } | null {
+ return this._filteredUtforandeVerksamheter$.value?.length
? {
- utforandeverksamhetIds: this._filteredUtforandeVerksamheter$
- .getValue()
- .map(utforandeVerksamhet => utforandeVerksamhet.id),
+ utforandeverksamhetIds: this._filteredUtforandeVerksamheter$.value.map(
+ utforandeVerksamhet => utforandeVerksamhet.id
+ ),
}
: null;
+ }
- switch (type) {
- case 'avrop':
- return {
- ...tjanstKoder,
- ...kommunKoder,
- ...utforandeverksamhetIds,
- page: this._page$.getValue().toString(),
- limit: this._limit$.getValue().toString(),
- };
- case 'kommuner':
- return {
- ...tjanstKoder,
- ...utforandeverksamhetIds,
- };
- case 'tjanster':
- return {
- ...kommunKoder,
- ...utforandeverksamhetIds,
- };
- case 'utforandeVerksamheter':
- return {
- ...tjanstKoder,
- ...kommunKoder,
- };
- default:
- return {};
- }
+ private get filtersForAvrop(): Params {
+ return {
+ ...this.tjanstKoder,
+ ...this.kommunKoder,
+ ...this.utforandeverksamhetIds,
+ page: this._page$.value.toString(),
+ limit: this._limit$.value.toString(),
+ };
+ }
+
+ private get filtersForTjanster(): Params {
+ return {
+ ...this.kommunKoder,
+ ...this.utforandeverksamhetIds,
+ };
+ }
+
+ private get filtersForUtforandeVerksamheter(): Params {
+ return {
+ ...this.tjanstKoder,
+ ...this.kommunKoder,
+ };
+ }
+
+ private get filtersForKommuner(): Params {
+ return {
+ ...this.tjanstKoder,
+ ...this.utforandeverksamhetIds,
+ };
}
public setSelectedAvrop(deltagare: Avrop[]): void {
diff --git a/apps/mina-sidor-fa/src/app/shared/utils/uuid.ts b/apps/mina-sidor-fa/src/app/shared/utils/uuid.ts
new file mode 100644
index 0000000..6fdfda8
--- /dev/null
+++ b/apps/mina-sidor-fa/src/app/shared/utils/uuid.ts
@@ -0,0 +1,8 @@
+// From https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid
+export function uuid(): string {
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+ const r = (Math.random() * 16) | 0,
+ v = c == 'x' ? r : (r & 0x3) | 0x8;
+ return v.toString(16);
+ });
+}
diff --git a/apps/mina-sidor-fa/src/styles/mixins/_form.scss b/apps/mina-sidor-fa/src/styles/mixins/_form.scss
new file mode 100644
index 0000000..ec2c7f5
--- /dev/null
+++ b/apps/mina-sidor-fa/src/styles/mixins/_form.scss
@@ -0,0 +1,25 @@
+@import 'variables/colors';
+@import 'variables/gutters';
+
+
+@mixin msfa__fieldset($legendAsHeading: true) {
+ margin: 0;
+ padding: 0;
+ border-width: 0;
+
+ legend {
+ position: relative;
+ text-align: left;
+
+ @if $legendAsHeading {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ padding-bottom: var(--digi--layout--gutter--xs);
+ margin: 0;
+ font-weight: var(--digi--typography--font-weight--bold);
+ font-size: var(--digi--typography--font-size--s);
+ border-bottom: 1px solid var(--digi--ui--color--background--off);
+ }
+ }
+}
diff --git a/apps/mina-sidor-fa/src/styles/styles.scss b/apps/mina-sidor-fa/src/styles/styles.scss
index b6d15fd..2868a73 100644
--- a/apps/mina-sidor-fa/src/styles/styles.scss
+++ b/apps/mina-sidor-fa/src/styles/styles.scss
@@ -1,4 +1,5 @@
@import '@digi/core/dist/digi/digi.css';
+@import '~@angular/cdk/overlay-prebuilt.css';
@import 'mixins/a11y';
@import 'mixins/backdrop';
@import 'mixins/icon';
diff --git a/package-lock.json b/package-lock.json
index 98dd381..8ec39b8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,11 @@
{
"name": "mina-sidor-fa-web",
- "version": "1.5.0",
+ "version": "1.5.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
- "name": "mina-sidor-fa-web",
- "version": "1.5.0",
+ "version": "1.5.1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -25,7 +24,6 @@
"@digi/core": "^9.4.0",
"@digi/styles": "^6.0.2",
"@nrwl/angular": "11.5.1",
- "angular2-uuid": "^1.1.1",
"date-fns": "^2.22.1",
"ngx-markdown": "^11.1.3",
"rxjs": "~6.6.3",
@@ -4952,12 +4950,6 @@
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
"dev": true
},
- "node_modules/angular2-uuid": {
- "version": "1.1.1",
- "resolved": "http://nexus.arbetsformedlingen.se/repository/npm/angular2-uuid/-/angular2-uuid-1.1.1.tgz",
- "integrity": "sha1-cvA81TK39AAy6x7PufhFc4S+lW4=",
- "license": "MIT"
- },
"node_modules/ansi-colors": {
"version": "4.1.1",
"resolved": "http://nexus.arbetsformedlingen.se/repository/npm/ansi-colors/-/ansi-colors-4.1.1.tgz",
@@ -36731,11 +36723,6 @@
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
"dev": true
},
- "angular2-uuid": {
- "version": "1.1.1",
- "resolved": "http://nexus.arbetsformedlingen.se/repository/npm/angular2-uuid/-/angular2-uuid-1.1.1.tgz",
- "integrity": "sha1-cvA81TK39AAy6x7PufhFc4S+lW4="
- },
"ansi-colors": {
"version": "4.1.1",
"resolved": "http://nexus.arbetsformedlingen.se/repository/npm/ansi-colors/-/ansi-colors-4.1.1.tgz",
diff --git a/package.json b/package.json
index e6ce3e6..5d46fa2 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,6 @@
"@digi/core": "^9.4.0",
"@digi/styles": "^6.0.2",
"@nrwl/angular": "11.5.1",
- "angular2-uuid": "^1.1.1",
"date-fns": "^2.22.1",
"ngx-markdown": "^11.1.3",
"rxjs": "~6.6.3",