Merge pull request #14 in TEA/dafa-web-monorepo from feature/more-mock-api-fixes to develop
Squashed commit of the following: commit 9473ca4e23eb6c5967d9df3403cc071d48e0ab73 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Jun 1 08:18:39 2021 +0200 Adding footer commit 8f13809ad3928fd09fd67d713a61c2ca4ef27bc4 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Tue Jun 1 06:57:34 2021 +0200 Added footer commit ee8a5be048786843e3c5672368a0663ead424852 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Mon May 31 16:07:14 2021 +0200 Added size to edit icon commit b8e99713bc0190075cfe201f8cd515dca78e184e Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Mon May 24 15:54:15 2021 +0200 Renamed create account to employee form and fixed some validation commit 935509bc5dd6bc7f6533b580197da2f8c15affc3 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Mon May 24 08:28:40 2021 +0200 More changes to mock-api and views commit d0bb8e1c0130c996ee89413f5ddda015fcf49ec5 Author: Erik Tiekstra <erik.tiekstra@arbetsformedlingen.se> Date: Fri May 21 11:22:40 2021 +0200 Modified mock-api and implemented a part inside employee-list
This commit is contained in:
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"angular.enable-strict-mode-prompt": false
|
||||||
|
}
|
||||||
@@ -13,5 +13,7 @@
|
|||||||
></digi-ng-navigation-breadcrumbs>
|
></digi-ng-navigation-breadcrumbs>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<dafa-footer class="dafa__footer"></dafa-footer>
|
||||||
</div>
|
</div>
|
||||||
<dafa-toast-list></dafa-toast-list>
|
<dafa-toast-list></dafa-toast-list>
|
||||||
|
|||||||
@@ -3,22 +3,24 @@
|
|||||||
@import 'variables/gutters';
|
@import 'variables/gutters';
|
||||||
|
|
||||||
.dafa {
|
.dafa {
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
overflow: hidden;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
|
height: 100vh;
|
||||||
grid-template-columns: 15rem 1fr;
|
grid-template-columns: 15rem 1fr;
|
||||||
grid-template-rows: $dafa__navigation-height 1fr;
|
grid-template-rows: auto 1fr auto;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
'header header'
|
'header header'
|
||||||
'sidebar content';
|
'sidebar content'
|
||||||
|
'footer footer';
|
||||||
|
|
||||||
@media (min-width: $digi--layout--breakpoint--m) {
|
// @media (min-width: $digi--layout--breakpoint--m) {
|
||||||
grid-template-rows: $dafa__navigation-height-large 1fr;
|
// grid-template-rows: $dafa__navigation-height-large 1fr auto;
|
||||||
}
|
// }
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__sidebar {
|
&__sidebar {
|
||||||
@@ -30,11 +32,16 @@
|
|||||||
&__content {
|
&__content {
|
||||||
grid-area: content;
|
grid-area: content;
|
||||||
padding: var(--digi--layout--gutter) $digi--layout--gutter--l $digi--layout--gutter--xxl;
|
padding: var(--digi--layout--gutter) $digi--layout--gutter--l $digi--layout--gutter--xxl;
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__breadcrumbs {
|
&__breadcrumbs {
|
||||||
display: block;
|
display: block;
|
||||||
margin-bottom: var(--digi--layout--gutter);
|
margin-bottom: var(--digi--layout--gutter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
grid-area: footer;
|
||||||
|
background-color: var(--digi--ui--color--primary);
|
||||||
|
min-height: 10rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { CustomErrorHandler } from '@dafa-interceptors/custom-error-handler.modu
|
|||||||
import { MarkdownModule } from 'ngx-markdown';
|
import { MarkdownModule } from 'ngx-markdown';
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
|
import { FooterModule } from './components/footer/footer.module';
|
||||||
import { NavigationModule } from './components/navigation/navigation.module';
|
import { NavigationModule } from './components/navigation/navigation.module';
|
||||||
import { SidebarModule } from './components/sidebar/sidebar.module';
|
import { SidebarModule } from './components/sidebar/sidebar.module';
|
||||||
import { SkipToContentModule } from './components/skip-to-content/skip-to-content.module';
|
import { SkipToContentModule } from './components/skip-to-content/skip-to-content.module';
|
||||||
@@ -23,6 +24,7 @@ import { ToastListModule } from './components/toast-list/toast-list.module';
|
|||||||
NavigationModule,
|
NavigationModule,
|
||||||
SidebarModule,
|
SidebarModule,
|
||||||
ToastListModule,
|
ToastListModule,
|
||||||
|
FooterModule,
|
||||||
MarkdownModule.forRoot({ loader: HttpClient }),
|
MarkdownModule.forRoot({ loader: HttpClient }),
|
||||||
DigiNgNavigationBreadcrumbsModule,
|
DigiNgNavigationBreadcrumbsModule,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<footer class="footer">
|
||||||
|
<div class="footer__logo-wrapper">
|
||||||
|
<a class="footer__logo-link" href="/">
|
||||||
|
<img class="footer__logo" src="/assets/logo/arbetsformedlingen-light.svg" alt="Arbetsförmedlingen" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
.footer {
|
||||||
|
background-color: var(--digi--ui--color--background--profile);
|
||||||
|
padding: var(--digi--layout--gutter);
|
||||||
|
|
||||||
|
&__logo-wrapper {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__logo {
|
||||||
|
height: 2rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { IconModule } from '@dafa-shared/components/icon/icon.module';
|
||||||
|
import { FooterComponent } from './footer.component';
|
||||||
|
|
||||||
|
describe('FooterComponent', () => {
|
||||||
|
let component: FooterComponent;
|
||||||
|
let fixture: ComponentFixture<FooterComponent>;
|
||||||
|
|
||||||
|
beforeEach(
|
||||||
|
waitForAsync(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [FooterComponent],
|
||||||
|
imports: [RouterTestingModule, IconModule],
|
||||||
|
}).compileComponents();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(FooterComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'dafa-footer',
|
||||||
|
templateUrl: './footer.component.html',
|
||||||
|
styleUrls: ['./footer.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class FooterComponent {}
|
||||||
11
apps/dafa-web/src/app/components/footer/footer.module.ts
Normal file
11
apps/dafa-web/src/app/components/footer/footer.module.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
import { FooterComponent } from './footer.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [FooterComponent],
|
||||||
|
imports: [CommonModule, RouterModule],
|
||||||
|
exports: [FooterComponent],
|
||||||
|
})
|
||||||
|
export class FooterModule {}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
@media print {
|
||||||
|
.footer {
|
||||||
|
border-bottom-width: 0;
|
||||||
|
padding: var(--digi--layout--gutter) 0;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
@import 'variables/colors';
|
@import 'variables/colors';
|
||||||
|
@import 'variables/navigation';
|
||||||
@import 'mixins/list';
|
@import 'mixins/list';
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: $dafa__navigation-height-large;
|
||||||
|
|
||||||
&__list {
|
&__list {
|
||||||
@include dafa__reset-list;
|
@include dafa__reset-list;
|
||||||
|
|||||||
19
apps/dafa-web/src/app/data/models/authorization.model.ts
Normal file
19
apps/dafa-web/src/app/data/models/authorization.model.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Authorization as AuthorizationEnum } from '@dafa-enums/authorization.enum';
|
||||||
|
|
||||||
|
export interface Authorization {
|
||||||
|
id: string;
|
||||||
|
name: AuthorizationEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AuthorizationApiResponse {
|
||||||
|
id: string;
|
||||||
|
name: AuthorizationEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapAuthorizationApiResponseToAuthorization(data: AuthorizationApiResponse): Authorization {
|
||||||
|
const { id, name } = data;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,27 +1,22 @@
|
|||||||
import { mapPegaAuthorizationToAuthorization, PegaAuthorization } from '@dafa-enums/authorization.enum';
|
|
||||||
import { Service } from '@dafa-enums/service.enum';
|
|
||||||
import { Participant } from './participant.model';
|
import { Participant } from './participant.model';
|
||||||
|
import { Service } from './service.model';
|
||||||
import { User, UserApiResponse } from './user.model';
|
import { User, UserApiResponse } from './user.model';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
||||||
export interface Employee extends User {
|
export interface Employee extends User {
|
||||||
languages: string[];
|
languages: string[];
|
||||||
outOfOffice: {
|
|
||||||
start: Date;
|
|
||||||
end: Date;
|
|
||||||
}[];
|
|
||||||
participants: Participant[];
|
participants: Participant[];
|
||||||
services: Service[];
|
services: Service[];
|
||||||
active: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmployeeApiResponse extends UserApiResponse {
|
export interface EmployeeApiResponse extends UserApiResponse {
|
||||||
active: boolean;
|
|
||||||
services: Service[];
|
services: Service[];
|
||||||
languages: string[];
|
languages: string[];
|
||||||
participants: Participant[];
|
participants: Participant[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
|
export interface EmployeeApiRequestData extends Employee {}
|
||||||
|
|
||||||
export interface PegaEmployeesApiResponse {
|
export interface PegaEmployeesApiResponse {
|
||||||
pxMore: string;
|
pxMore: string;
|
||||||
pxObjClass: string;
|
pxObjClass: string;
|
||||||
@@ -44,7 +39,6 @@ export interface PegaEmployeeApiResponse {
|
|||||||
pyOrganization: string;
|
pyOrganization: string;
|
||||||
pyOrgDivision: string;
|
pyOrgDivision: string;
|
||||||
pyOrgUnit: string;
|
pyOrgUnit: string;
|
||||||
pyTelephone: string;
|
|
||||||
pyUserIdentifier: string;
|
pyUserIdentifier: string;
|
||||||
pyUserName: string;
|
pyUserName: string;
|
||||||
}
|
}
|
||||||
@@ -52,7 +46,6 @@ export interface PegaEmployeeApiResponse {
|
|||||||
export interface PegaEmployeeApiRequestData {
|
export interface PegaEmployeeApiRequestData {
|
||||||
pyFirstName: string;
|
pyFirstName: string;
|
||||||
pyLastName: string;
|
pyLastName: string;
|
||||||
pyTelephone: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PegaEmployeeApiPostResponse {
|
export interface PegaEmployeeApiPostResponse {
|
||||||
@@ -61,15 +54,17 @@ export interface PegaEmployeeApiPostResponse {
|
|||||||
pyFirstName: string;
|
pyFirstName: string;
|
||||||
pyHasError: 'true' | 'false';
|
pyHasError: 'true' | 'false';
|
||||||
pyLastName: string;
|
pyLastName: string;
|
||||||
pyTelephone: string;
|
|
||||||
pyUserIdentifier: string;
|
pyUserIdentifier: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapEmployeeToEmployeeApiRequestData(data: Employee): PegaEmployeeApiRequestData {
|
export function mapEmployeeToEmployeeApiRequestData(data: Employee): EmployeeApiRequestData {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapEmployeeToPegaEmployeeApiRequestData(data: Employee): PegaEmployeeApiRequestData {
|
||||||
return {
|
return {
|
||||||
pyFirstName: data.firstName,
|
pyFirstName: data.firstName,
|
||||||
pyLastName: data.lastName,
|
pyLastName: data.lastName,
|
||||||
pyTelephone: data.phone,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,59 +74,41 @@ export function mapPegaEmployeeReponseToEmployee(data: PegaEmployeeApiResponse):
|
|||||||
lastName: data.pyLastName,
|
lastName: data.pyLastName,
|
||||||
firstName: data.pyFirstName,
|
firstName: data.pyFirstName,
|
||||||
fullName: `${data.pyFirstName} ${data.pyLastName}`,
|
fullName: `${data.pyFirstName} ${data.pyLastName}`,
|
||||||
organization: {
|
organizations: [
|
||||||
id: '',
|
{
|
||||||
name: data.pyOrganization,
|
id: '',
|
||||||
kaNumber: null,
|
name: data.pyOrganization,
|
||||||
address: {
|
kaNumber: null,
|
||||||
street: null,
|
address: {
|
||||||
houseNumber: null,
|
street: null,
|
||||||
postalCode: null,
|
houseNumber: null,
|
||||||
city: null,
|
postalCode: null,
|
||||||
kommun: null,
|
city: null,
|
||||||
|
kommun: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
phone: data.pyTelephone,
|
authorizations: null,
|
||||||
email: '',
|
// authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
|
||||||
authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
|
|
||||||
services: [],
|
services: [],
|
||||||
languages: [],
|
languages: [],
|
||||||
outOfOffice: null,
|
|
||||||
ssn: '',
|
ssn: '',
|
||||||
participants: [],
|
participants: [],
|
||||||
active: true,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapEmployeeReponseToEmployee(data: EmployeeApiResponse): Employee {
|
export function mapEmployeeReponseToEmployee(data: EmployeeApiResponse): Employee {
|
||||||
const {
|
const { id, firstName, lastName, ssn, services, languages, organizations, authorizations, participants } = data;
|
||||||
id,
|
|
||||||
firstName,
|
|
||||||
lastName,
|
|
||||||
phone,
|
|
||||||
email,
|
|
||||||
ssn,
|
|
||||||
active,
|
|
||||||
services,
|
|
||||||
languages,
|
|
||||||
organization,
|
|
||||||
authorizations,
|
|
||||||
participants,
|
|
||||||
} = data;
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
fullName: `${firstName} ${lastName}`,
|
fullName: `${firstName} ${lastName}`,
|
||||||
organization,
|
organizations,
|
||||||
phone,
|
|
||||||
email,
|
|
||||||
authorizations,
|
authorizations,
|
||||||
services,
|
services,
|
||||||
languages,
|
languages,
|
||||||
outOfOffice: null,
|
|
||||||
ssn,
|
ssn,
|
||||||
participants,
|
participants,
|
||||||
active,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
19
apps/dafa-web/src/app/data/models/service.model.ts
Normal file
19
apps/dafa-web/src/app/data/models/service.model.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { Service as ServiceEnum } from '@dafa-enums/service.enum';
|
||||||
|
|
||||||
|
export interface Service {
|
||||||
|
id: string;
|
||||||
|
name: ServiceEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceApiResponse {
|
||||||
|
id: string;
|
||||||
|
name: ServiceEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mapServiceApiResponseToService(data: ServiceApiResponse): Service {
|
||||||
|
const { id, name } = data;
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Authorization, mapPegaAuthorizationToAuthorization, PegaAuthorization } from '@dafa-enums/authorization.enum';
|
import { Authorization } from './authorization.model';
|
||||||
import { Organization } from './organization.model';
|
import { Organization } from './organization.model';
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
@@ -7,9 +7,7 @@ export interface User {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
fullName: string;
|
fullName: string;
|
||||||
ssn: string;
|
ssn: string;
|
||||||
phone: string;
|
organizations: Organization[];
|
||||||
email: string;
|
|
||||||
organization: Organization;
|
|
||||||
authorizations: Authorization[];
|
authorizations: Authorization[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,9 +16,7 @@ export interface UserApiResponse {
|
|||||||
firstName: string;
|
firstName: string;
|
||||||
lastName: string;
|
lastName: string;
|
||||||
ssn: string;
|
ssn: string;
|
||||||
phone: string;
|
organizations: Organization[];
|
||||||
email: string;
|
|
||||||
organization: Organization;
|
|
||||||
authorizations: Authorization[];
|
authorizations: Authorization[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,30 +31,20 @@ export interface PegaUserApiResponse {
|
|||||||
pyOrganization: string;
|
pyOrganization: string;
|
||||||
pyOrgDivision: string;
|
pyOrgDivision: string;
|
||||||
pyOrgUnit: string;
|
pyOrgUnit: string;
|
||||||
pyTelephone: string;
|
|
||||||
pyUserIdentifier: string;
|
pyUserIdentifier: string;
|
||||||
pyUserName: string;
|
pyUserName: string;
|
||||||
pyAccessGroupsAdditional: string[];
|
pyAccessGroupsAdditional: string[];
|
||||||
pyAddresses: {
|
|
||||||
Email: {
|
|
||||||
pxObjClass: string;
|
|
||||||
pxSubscript: string;
|
|
||||||
pyEmailAddress: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mapUserApiResponseToUser(data: UserApiResponse): User {
|
export function mapUserApiResponseToUser(data: UserApiResponse): User {
|
||||||
const { id, firstName, lastName, ssn, organization, phone, email, authorizations } = data;
|
const { id, firstName, lastName, ssn, organizations, authorizations } = data;
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
firstName,
|
firstName,
|
||||||
lastName,
|
lastName,
|
||||||
fullName: `${firstName} ${lastName}`,
|
fullName: `${firstName} ${lastName}`,
|
||||||
ssn,
|
ssn,
|
||||||
organization,
|
organizations,
|
||||||
phone,
|
|
||||||
email,
|
|
||||||
authorizations,
|
authorizations,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -70,20 +56,21 @@ export function mapPegaUserApiReponseToUser(data: PegaUserApiResponse): User {
|
|||||||
firstName: data.pyFirstName,
|
firstName: data.pyFirstName,
|
||||||
fullName: `${data.pyFirstName} ${data.pyLastName}`,
|
fullName: `${data.pyFirstName} ${data.pyLastName}`,
|
||||||
ssn: null,
|
ssn: null,
|
||||||
organization: {
|
organizations: [
|
||||||
id: '',
|
{
|
||||||
name: data.pyOrganization,
|
id: '',
|
||||||
kaNumber: null,
|
name: data.pyOrganization,
|
||||||
address: {
|
kaNumber: null,
|
||||||
street: null,
|
address: {
|
||||||
houseNumber: null,
|
street: null,
|
||||||
postalCode: null,
|
houseNumber: null,
|
||||||
city: null,
|
postalCode: null,
|
||||||
kommun: null,
|
city: null,
|
||||||
|
kommun: null,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
phone: data.pyTelephone,
|
authorizations: null,
|
||||||
email: data.pyAddresses.Email.pyEmailAddress,
|
// authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
|
||||||
authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ const routes: Routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'skapa-konto',
|
path: 'skapa-konto',
|
||||||
loadChildren: () => import('./pages/create-account/create-account.module').then(m => m.CreateAccountModule),
|
loadChildren: () => import('./pages/employee-form/employee-form.module').then(m => m.EmployeeFormModule),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'redigera-konto/:id',
|
||||||
|
loadChildren: () => import('./pages/employee-form/employee-form.module').then(m => m.EmployeeFormModule),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,99 +0,0 @@
|
|||||||
<section class="create-account">
|
|
||||||
<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()">
|
|
||||||
<div class="create-account__block">
|
|
||||||
<h2>Personuppgifter</h2>
|
|
||||||
<digi-ng-form-input
|
|
||||||
class="create-account__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
|
|
||||||
class="create-account__input"
|
|
||||||
formControlName="lastName"
|
|
||||||
afLabel="Efternamn"
|
|
||||||
afInvalidMessage="Efternamn är obligatoriskt"
|
|
||||||
[afDisableValidStyle]="true"
|
|
||||||
[afInvalid]="lastNameControl.invalid && lastNameControl.dirty"
|
|
||||||
></digi-ng-form-input>
|
|
||||||
<digi-ng-form-input
|
|
||||||
class="create-account__input"
|
|
||||||
formControlName="ssn"
|
|
||||||
afLabel="Personnummer"
|
|
||||||
[afInvalidMessage]="ssnControl.errors?.message || ''"
|
|
||||||
[afDisableValidStyle]="true"
|
|
||||||
[afInvalid]="ssnControl.invalid && ssnControl.dirty"
|
|
||||||
></digi-ng-form-input>
|
|
||||||
<digi-ng-form-input
|
|
||||||
class="create-account__input"
|
|
||||||
formControlName="phone"
|
|
||||||
afLabel="Telefonnummer"
|
|
||||||
[afInvalidMessage]="phoneControl.errors?.message || ''"
|
|
||||||
[afDisableValidStyle]="true"
|
|
||||||
[afInvalid]="phoneControl.invalid && phoneControl.dirty"
|
|
||||||
></digi-ng-form-input>
|
|
||||||
</div>
|
|
||||||
<div class="create-account__block">
|
|
||||||
<h2>Tjänst</h2>
|
|
||||||
|
|
||||||
<digi-ng-form-select afPlaceholder=" " afLabel="Välj tjänst" formControlName="service" [afSelectItems]="list">
|
|
||||||
</digi-ng-form-select>
|
|
||||||
</div>
|
|
||||||
<fieldset class="create-account__fieldset">
|
|
||||||
<legend>Tilldela behörigheter</legend>
|
|
||||||
|
|
||||||
<div class="create-account__permission-checkbox">
|
|
||||||
<digi-ng-form-checkbox formControlName="permissions" afLabel="Välj administrera behörigheter">
|
|
||||||
</digi-ng-form-checkbox>
|
|
||||||
<digi-ng-popover class="create-account__popover">
|
|
||||||
<p>Jag har tillräckligt med utrymme för att öppnas till höger (inline-start).</p>
|
|
||||||
<a href="#">Tab to me</a>
|
|
||||||
</digi-ng-popover>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="create-account__permission-checkbox">
|
|
||||||
<digi-ng-form-checkbox formControlName="participant" afLabel="Välj ta emot deltagare"></digi-ng-form-checkbox>
|
|
||||||
<digi-ng-popover class="create-account__popover">
|
|
||||||
<p>Jag har tillräckligt med utrymme för att öppnas till höger (inline-start).</p>
|
|
||||||
<a href="#">Tab to me</a>
|
|
||||||
</digi-ng-popover>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="create-account__permission-checkbox">
|
|
||||||
<digi-ng-form-checkbox
|
|
||||||
formControlName="infoParticipant"
|
|
||||||
afLabel="Välj rapportering, planering och infomration om deltagare"
|
|
||||||
>
|
|
||||||
</digi-ng-form-checkbox>
|
|
||||||
<digi-ng-popover class="create-account__popover">
|
|
||||||
<p>Jag har tillräckligt med utrymme för att öppnas till höger (inline-start).</p>
|
|
||||||
<a href="#">Tab to me</a>
|
|
||||||
</digi-ng-popover>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="create-account__permission-checkbox">
|
|
||||||
<digi-ng-form-checkbox formControlName="orderBills" afLabel="Välj administrera ordrar och fakturor">
|
|
||||||
</digi-ng-form-checkbox>
|
|
||||||
<digi-ng-popover class="create-account__popover">
|
|
||||||
<p>Jag har tillräckligt med utrymme för att öppnas till höger (inline-start).</p>
|
|
||||||
<a href="#">Tab to me</a>
|
|
||||||
</digi-ng-popover>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<div class="create-account__footer">
|
|
||||||
<digi-button af-type="reset" af-variation="secondary">Avbryt</digi-button>
|
|
||||||
<digi-button af-type="submit">Registrera konto</digi-button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
@import 'mixins/list';
|
|
||||||
|
|
||||||
.create-account {
|
|
||||||
&__block {
|
|
||||||
max-width: var(--digi--typography--text--max-width);
|
|
||||||
}
|
|
||||||
&__combined-inputs {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--digi--layout--gutter);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__input {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
margin-bottom: var(--digi--layout--gutter);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__permission-checkbox {
|
|
||||||
display: flex;
|
|
||||||
height: 5rem;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__fieldset {
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
margin-top: var(--digi--layout--gutter);
|
|
||||||
|
|
||||||
legend {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0;
|
|
||||||
font-weight: var(--digi--typography--font-weight--bold);
|
|
||||||
font-size: 1.5rem;
|
|
||||||
padding-bottom: var(--digi--layout--gutter--s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__pending-out-of-office-list {
|
|
||||||
@include dafa__reset-list;
|
|
||||||
margin-top: var(--digi--layout--gutter);
|
|
||||||
|
|
||||||
li {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
gap: var(--digi--layout--gutter--s);
|
|
||||||
padding: var(--digi--layout--gutter--s);
|
|
||||||
|
|
||||||
&:nth-child(odd) {
|
|
||||||
background-color: var(--digi--ui--color--background--tertiary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__footer {
|
|
||||||
margin-top: var(--digi--layout--gutter);
|
|
||||||
display: flex;
|
|
||||||
gap: var(--digi--layout--gutter);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__popover {
|
|
||||||
margin-left: var(--digi--layout--gutter);
|
|
||||||
|
|
||||||
::ng-deep .digi-ng-popover__container {
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import { FormSelectBaseItem } from '@af/digi-ng/_form/form-select-base';
|
|
||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
|
||||||
import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { Service } from '@dafa-enums/service.enum';
|
|
||||||
import { EmployeeService } from '@dafa-services/api/employee.service';
|
|
||||||
import { RequiredValidator } from '@dafa-validators/required.validator';
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'dafa-create-account',
|
|
||||||
templateUrl: './create-account.component.html',
|
|
||||||
styleUrls: ['./create-account.component.scss'],
|
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
||||||
})
|
|
||||||
export class CreateAccountComponent {
|
|
||||||
private _searchValue$ = new BehaviorSubject<string>('');
|
|
||||||
|
|
||||||
formGroup: FormGroup;
|
|
||||||
todaysDate = new Date();
|
|
||||||
|
|
||||||
list: FormSelectBaseItem[] = [
|
|
||||||
{
|
|
||||||
name: Service.STOM,
|
|
||||||
value: '1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: Service.KVL,
|
|
||||||
value: '2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: Service.KROM,
|
|
||||||
value: '3',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor(private formBuilder: FormBuilder, private employeeService: EmployeeService, private router: Router) {
|
|
||||||
this.formGroup = this.formBuilder.group({
|
|
||||||
firstName: this.formBuilder.control('', [RequiredValidator('Förnamn')]),
|
|
||||||
lastName: this.formBuilder.control('', [RequiredValidator('Efternamn')]),
|
|
||||||
phone: this.formBuilder.control('', [RequiredValidator('Telefonnummer')]),
|
|
||||||
// ssn: this.formBuilder.control('', [RequiredValidator('Personnummer'), SocialSecurityNumberValidator()]),
|
|
||||||
// employeeId: this.formBuilder.control('', [RequiredValidator('Personal-ID')]),
|
|
||||||
ssn: this.formBuilder.control(''),
|
|
||||||
employeeId: this.formBuilder.control(''),
|
|
||||||
service: this.formBuilder.control(''),
|
|
||||||
permissions: this.formBuilder.control(false),
|
|
||||||
participant: this.formBuilder.control(false),
|
|
||||||
infoParticipant: this.formBuilder.control(false),
|
|
||||||
orderBills: this.formBuilder.control(false),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSearchSubmit(): void {
|
|
||||||
// skicka searchvalue till en service och filtrera
|
|
||||||
}
|
|
||||||
|
|
||||||
handleSearchInput($event: CustomEvent): void {
|
|
||||||
this._searchValue$.next($event.detail.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
get formselectItem(): FormSelectBaseItem[] {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: Service.STOM,
|
|
||||||
value: '1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: Service.KVL,
|
|
||||||
value: '2',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: Service.KROM,
|
|
||||||
value: '3',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
get firstNameControl(): AbstractControl {
|
|
||||||
return this.formGroup.get('firstName');
|
|
||||||
}
|
|
||||||
get lastNameControl(): AbstractControl {
|
|
||||||
return this.formGroup.get('lastName');
|
|
||||||
}
|
|
||||||
get ssnControl(): AbstractControl {
|
|
||||||
return this.formGroup.get('ssn');
|
|
||||||
}
|
|
||||||
get phoneControl(): AbstractControl {
|
|
||||||
return this.formGroup.get('phone');
|
|
||||||
}
|
|
||||||
|
|
||||||
private _markFormAsDirty(): void {
|
|
||||||
Object.keys(this.formGroup.controls).forEach(control => {
|
|
||||||
this.formGroup.get(control).markAsDirty();
|
|
||||||
this.formGroup.get(control).markAsTouched();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
submitForm(): void {
|
|
||||||
if (this.formGroup.valid) {
|
|
||||||
const submittableValues = {
|
|
||||||
...this.formGroup.value,
|
|
||||||
fullName: `${this.firstNameControl.value} ${this.lastNameControl.value}`,
|
|
||||||
};
|
|
||||||
|
|
||||||
delete submittableValues.outOfOfficeStart;
|
|
||||||
delete submittableValues.outOfOfficeEnd;
|
|
||||||
|
|
||||||
const post = this.employeeService.postNewEmployee(submittableValues).subscribe({
|
|
||||||
next: id => {
|
|
||||||
this.router.navigate(['/administration', 'personal', id]);
|
|
||||||
},
|
|
||||||
complete: () => {
|
|
||||||
post.unsubscribe();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// this.formGroup.reset();
|
|
||||||
} else {
|
|
||||||
console.error('Form is invalid, do something...');
|
|
||||||
this._markFormAsDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,76 +7,58 @@
|
|||||||
perferendis commodi.
|
perferendis commodi.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="staff-card__contents">
|
<div class="employee-card__contents">
|
||||||
<div class="staff-card__column">
|
<div class="employee-card__column">
|
||||||
<h2>Kontaktuppgifter</h2>
|
<h2>Kontaktuppgifter</h2>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
|
<dt>Namn</dt>
|
||||||
|
<dd *ngIf="detailedEmployeeData.fullName; else emptyDD">{{ detailedEmployeeData.fullName }}</dd>
|
||||||
<dt>Personnummer</dt>
|
<dt>Personnummer</dt>
|
||||||
<dd *ngIf="detailedEmployeeData.ssn; else emptyDD">{{ detailedEmployeeData.ssn }}</dd>
|
<dd *ngIf="detailedEmployeeData.ssn; else emptyDD">{{ detailedEmployeeData.ssn }}</dd>
|
||||||
<dt>Telefonnummer</dt>
|
|
||||||
<dd *ngIf="detailedEmployeeData.phone; else emptyDD">
|
|
||||||
<a [attr.href]="'tel:' + detailedEmployeeData.phone">{{ detailedEmployeeData.phone }}</a>
|
|
||||||
</dd>
|
|
||||||
<dt>Epost adress</dt>
|
|
||||||
<dd *ngIf="detailedEmployeeData.email; else emptyDD">
|
|
||||||
<a [attr.href]="'mailto:' + detailedEmployeeData.email">{{ detailedEmployeeData.email }}</a>
|
|
||||||
</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="staff-card__column">
|
<div class="employee-card__column">
|
||||||
<h2>Uppgifter om arbete</h2>
|
<h2>Uppgifter om arbete</h2>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Utförandeverksamhet</dt>
|
|
||||||
<dd *ngIf="detailedEmployeeData.organization; else emptyDD">
|
|
||||||
{{ detailedEmployeeData.organization.address.city }}
|
|
||||||
</dd>
|
|
||||||
<dt>Behörigheter</dt>
|
<dt>Behörigheter</dt>
|
||||||
<dd *ngIf="detailedEmployeeData.authorizations?.length; else emptyDD">
|
<ng-container *ngIf="detailedEmployeeData.authorizations.length; else emptyDD">
|
||||||
{{ detailedEmployeeData.authorizations.join(', ') }}
|
<dd *ngFor="let authorization of detailedEmployeeData.authorizations">{{ authorization.name }}</dd>
|
||||||
</dd>
|
</ng-container>
|
||||||
<dt>Frånvaroperiod</dt>
|
<dt>Tjänster</dt>
|
||||||
<ng-container *ngIf="detailedEmployeeData.outOfOffice?.length; else emptyDD">
|
<ng-container *ngIf="detailedEmployeeData.services.length; else emptyDD">
|
||||||
<dd *ngFor="let date of detailedEmployeeData.outOfOffice">
|
<dd *ngFor="let service of detailedEmployeeData.services">{{ service.name }}</dd>
|
||||||
{{ date.start | localDate }} - {{ date.end | localDate }}
|
|
||||||
</dd>
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<dt>Tjänst</dt>
|
|
||||||
<dd *ngIf="detailedEmployeeData.services.length; else emptyDD">
|
|
||||||
{{ detailedEmployeeData.services.join(', ') }}
|
|
||||||
</dd>
|
|
||||||
<dt>Språk</dt>
|
|
||||||
<dd>{{ detailedEmployeeData.languages?.join(', ') }}</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="staff-card__column">
|
<div class="employee-card__column">
|
||||||
<h2>Utförande verksamhet</h2>
|
<h2>Utförande verksamheter</h2>
|
||||||
|
|
||||||
<ul *ngIf="detailedEmployeeData.agencies?.length" class="staff-card__agencies">
|
<ul *ngIf="detailedEmployeeData.organizations?.length" class="employee-card__organizations">
|
||||||
<li *ngFor="let agency of detailedEmployeeData.agencies" class="staff-card__agency">
|
<li *ngFor="let organization of detailedEmployeeData.organizations" class="employee-card__organization">
|
||||||
<h3>{{ agency.name }}</h3>
|
<h3>{{ organization.name }}</h3>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>KA-nummer</dt>
|
<dt>KA-nummer</dt>
|
||||||
<dd>{{ agency.kaNumber }}</dd>
|
<dd>{{ organization.kaNumber }}</dd>
|
||||||
<dt>Adress</dt>
|
<dt>Adress</dt>
|
||||||
<dd>{{ agency.address.street }} {{ agency.address.houseNumber }}</dd>
|
<dd>{{ organization.address.street }} {{ organization.address.houseNumber }}</dd>
|
||||||
<dd>{{ agency.address.postalCode }} {{ agency.address.city }}</dd>
|
<dd>{{ organization.address.postalCode }} {{ organization.address.city }}</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="staff-card__column">
|
<div class="employee-card__column">
|
||||||
<digi-ng-layout-expansion-panel>
|
<digi-ng-layout-expansion-panel>
|
||||||
<h3 style="margin-bottom: 0" data-slot-trigger>
|
<h3 style="margin-bottom: 0" data-slot-trigger>
|
||||||
Tilldelade deltagare ({{ detailedEmployeeData.participants?.length || 0 }})
|
Tilldelade deltagare ({{ detailedEmployeeData.participants?.length || 0 }})
|
||||||
</h3>
|
</h3>
|
||||||
<ng-container *ngIf="detailedEmployeeData.participants?.length; else noParticipantsInfo">
|
<ng-container *ngIf="detailedEmployeeData.participants?.length; else noParticipantsInfo">
|
||||||
<ul class="staff-card__participants">
|
<ul class="employee-card__participants">
|
||||||
<li *ngIf="detailedEmployeeData.participants.length > 1" class="staff-card__participant">
|
<li *ngIf="detailedEmployeeData.participants.length > 1" class="employee-card__participant">
|
||||||
<digi-form-checkbox
|
<digi-form-checkbox
|
||||||
af-variation="primary"
|
af-variation="primary"
|
||||||
af-label="Välj alla"
|
af-label="Välj alla"
|
||||||
@@ -88,7 +70,7 @@
|
|||||||
"
|
"
|
||||||
></digi-form-checkbox>
|
></digi-form-checkbox>
|
||||||
</li>
|
</li>
|
||||||
<li *ngFor="let participant of detailedEmployeeData.participants" class="staff-card__participant">
|
<li *ngFor="let participant of detailedEmployeeData.participants" class="employee-card__participant">
|
||||||
<digi-form-checkbox
|
<digi-form-checkbox
|
||||||
af-variation="primary"
|
af-variation="primary"
|
||||||
[afLabel]="participant.fullName"
|
[afLabel]="participant.fullName"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
&__contents {
|
&__contents {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: $digi--layout--gutter--l;
|
gap: $digi--layout--gutter--xl $digi--layout--gutter--l;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
@@ -37,14 +37,14 @@
|
|||||||
grid-column: 2;
|
grid-column: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__agencies {
|
&__organizations {
|
||||||
@include dafa__reset-list;
|
@include dafa__reset-list;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__agency {
|
&__organization {
|
||||||
border: 1px solid #333;
|
border: 1px solid #333;
|
||||||
padding: var(--digi--layout--gutter);
|
padding: var(--digi--layout--gutter);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
|||||||
})
|
})
|
||||||
export class EmployeeCardComponent extends UnsubscribeDirective {
|
export class EmployeeCardComponent extends UnsubscribeDirective {
|
||||||
detailedEmployeeData$: Observable<Employee>;
|
detailedEmployeeData$: Observable<Employee>;
|
||||||
|
authorizationsAsString$: Observable<string>;
|
||||||
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
|
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
|
||||||
|
|
||||||
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
|
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
<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>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<digi-typography>
|
||||||
|
<h2>Tjänst</h2>
|
||||||
|
</digi-typography>
|
||||||
|
|
||||||
|
<!-- TODO: Right now there are issues within digi-form-filter where Angular
|
||||||
|
attributes are not working. Also event-handling is not working.
|
||||||
|
The digi-team is notified -->
|
||||||
|
<digi-form-filter
|
||||||
|
af-id="employee-form-services"
|
||||||
|
af-name="Tjänst"
|
||||||
|
af-filter-button-text="Välj tjänst"
|
||||||
|
af-submit-button-text="Spara tjänster"
|
||||||
|
(afOnSubmitFilters)="addPendingServicesToFormControl()"
|
||||||
|
(afOnFocusOut)="addPendingServicesToFormControl()"
|
||||||
|
(afOnResetFilters)="resetPendingServices()"
|
||||||
|
>
|
||||||
|
<digi-form-checkbox
|
||||||
|
af-variation="primary"
|
||||||
|
af-label="Välj alla"
|
||||||
|
[afChecked]="pendingServices?.length"
|
||||||
|
[afIndeterminate]="pendingServices?.length !== services?.length"
|
||||||
|
(afOnChange)="togglePendingService(services, $event.detail.target.checked)"
|
||||||
|
></digi-form-checkbox>
|
||||||
|
<digi-form-checkbox
|
||||||
|
*ngFor="let service of services"
|
||||||
|
af-variation="primary"
|
||||||
|
[afLabel]="service.name"
|
||||||
|
[afValue]="service.id"
|
||||||
|
[afChecked]="pendingServices.includes(service)"
|
||||||
|
(afOnChange)="togglePendingService(service, $event.detail.target.checked)"
|
||||||
|
></digi-form-checkbox>
|
||||||
|
</digi-form-filter>
|
||||||
|
<digi-form-validation-message
|
||||||
|
class="employee-form__validation-message"
|
||||||
|
*ngIf="servicesControl.invalid && servicesControl.dirty"
|
||||||
|
af-variation="error"
|
||||||
|
>
|
||||||
|
{{ servicesControl.errors.message }}
|
||||||
|
</digi-form-validation-message>
|
||||||
|
|
||||||
|
<div class="employee-form__added-services">
|
||||||
|
<digi-typography>
|
||||||
|
<h3>Valda tjänster</h3>
|
||||||
|
</digi-typography>
|
||||||
|
<ul *ngIf="servicesControl.value?.length; else noServicesAdded" class="employee-form__services">
|
||||||
|
<li class="employee-form__service-item" *ngFor="let service of servicesControl.value">
|
||||||
|
<span>{{ service.name }}</span>
|
||||||
|
<digi-button af-variation="tertiary" (afOnClick)="removeServiceFromFormControl(service.id)">
|
||||||
|
<digi-icon-x-button slot="icon"></digi-icon-x-button>
|
||||||
|
</digi-button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ng-template #noServicesAdded>Inga tjänster vald.</ng-template>
|
||||||
|
</div>
|
||||||
|
</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
|
||||||
|
[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-ng-popover class="employee-form__popover">
|
||||||
|
<p>Info om behörighet</p>
|
||||||
|
</digi-ng-popover>
|
||||||
|
</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>
|
||||||
|
<digi-button af-type="submit">Registrera konto</digi-button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
@import 'mixins/list';
|
||||||
|
@import 'variables/gutters';
|
||||||
|
|
||||||
|
.employee-form {
|
||||||
|
&__block {
|
||||||
|
max-width: var(--digi--typography--text--max-width);
|
||||||
|
margin-bottom: $digi--layout--gutter--xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: var(--digi--layout--gutter);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__fieldset {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
|
||||||
|
legend {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: var(--digi--typography--font-weight--semibold);
|
||||||
|
font-size: var(--digi--typography--font-size--h2--desktop);
|
||||||
|
margin-bottom: var(--digi-typography--margin--h2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__validation-message {
|
||||||
|
display: block;
|
||||||
|
margin-top: var(--digi--layout--gutter--s);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__added-services {
|
||||||
|
margin-top: var(--digi--layout--gutter);
|
||||||
|
max-width: 50rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__services,
|
||||||
|
&__authorizations {
|
||||||
|
@include dafa__reset-list;
|
||||||
|
margin-bottom: var(--digi--layout--gutter);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__service-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--digi--layout--gutter--xs) var(--digi--layout--gutter--s);
|
||||||
|
|
||||||
|
&:nth-child(odd) {
|
||||||
|
background-color: var(--digi--ui--color--background--secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__authorization-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: var(--digi--layout--gutter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__error-list {
|
||||||
|
display: block;
|
||||||
|
margin-top: $digi--layout--gutter--l;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
margin-top: $digi--layout--gutter--xl;
|
||||||
|
display: flex;
|
||||||
|
gap: var(--digi--layout--gutter);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__popover {
|
||||||
|
margin-left: var(--digi--layout--gutter);
|
||||||
|
|
||||||
|
::ng-deep .digi-ng-popover__container {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,17 +9,17 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { CreateAccountComponent } from './create-account.component';
|
import { EmployeeFormComponent } from './employee-form.component';
|
||||||
|
|
||||||
describe('CreateAccountComponent', () => {
|
describe('EmployeeFormComponent', () => {
|
||||||
let component: CreateAccountComponent;
|
let component: EmployeeFormComponent;
|
||||||
let fixture: ComponentFixture<CreateAccountComponent>;
|
let fixture: ComponentFixture<EmployeeFormComponent>;
|
||||||
|
|
||||||
beforeEach(
|
beforeEach(
|
||||||
waitForAsync(() => {
|
waitForAsync(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
declarations: [CreateAccountComponent],
|
declarations: [EmployeeFormComponent],
|
||||||
imports: [
|
imports: [
|
||||||
RouterTestingModule,
|
RouterTestingModule,
|
||||||
HttpClientTestingModule,
|
HttpClientTestingModule,
|
||||||
@@ -36,7 +36,7 @@ describe('CreateAccountComponent', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
fixture = TestBed.createComponent(CreateAccountComponent);
|
fixture = TestBed.createComponent(EmployeeFormComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
import { FormSelectBaseItem } from '@af/digi-ng/_form/form-select-base';
|
||||||
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
|
import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { Authorization } from '@dafa-models/authorization.model';
|
||||||
|
import { Service } from '@dafa-models/service.model';
|
||||||
|
import { AuthorizationService } from '@dafa-services/api/authorizations.service';
|
||||||
|
import { EmployeeService } from '@dafa-services/api/employee.service';
|
||||||
|
import { ServiceService } from '@dafa-services/api/service.service';
|
||||||
|
import { SocialSecurityNumberValidator } from '@dafa-utils/validators/social-security-number.validator';
|
||||||
|
import { RequiredValidator } from '@dafa-validators/required.validator';
|
||||||
|
import { BehaviorSubject, Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'dafa-employee-form',
|
||||||
|
templateUrl: './employee-form.component.html',
|
||||||
|
styleUrls: ['./employee-form.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class EmployeeFormComponent {
|
||||||
|
services$: Observable<Service[]> = this.serviceService.services$;
|
||||||
|
authorizations$: Observable<Authorization[]> = this.authorizationService.authorizations$;
|
||||||
|
servicesSelectItems$: Observable<FormSelectBaseItem[]> = this.services$.pipe(
|
||||||
|
map(services => services.map(({ name, id }) => ({ name, value: id })))
|
||||||
|
);
|
||||||
|
private _pendingServices$ = new BehaviorSubject<Service[]>([]);
|
||||||
|
|
||||||
|
formGroup: FormGroup = this.formBuilder.group({
|
||||||
|
firstName: this.formBuilder.control('', [RequiredValidator('Förnamn')]),
|
||||||
|
lastName: this.formBuilder.control('', [RequiredValidator('Efternamn')]),
|
||||||
|
ssn: this.formBuilder.control('', [RequiredValidator('Personnummer'), SocialSecurityNumberValidator()]),
|
||||||
|
// services: this.formBuilder.control([], [RequiredValidator('en tjänst')]),
|
||||||
|
services: this.formBuilder.control([]),
|
||||||
|
authorizations: this.formBuilder.control([], [RequiredValidator('en behörighet')]),
|
||||||
|
});
|
||||||
|
todaysDate = new Date();
|
||||||
|
submitted = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private formBuilder: FormBuilder,
|
||||||
|
private employeeService: EmployeeService,
|
||||||
|
private serviceService: ServiceService,
|
||||||
|
private authorizationService: AuthorizationService,
|
||||||
|
private router: Router
|
||||||
|
) {
|
||||||
|
this.formGroup.valueChanges.subscribe(values => console.log(this.formGroup));
|
||||||
|
}
|
||||||
|
|
||||||
|
get pendingServices(): Service[] {
|
||||||
|
return this._pendingServices$.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
get firstNameControl(): AbstractControl {
|
||||||
|
return this.formGroup.get('firstName');
|
||||||
|
}
|
||||||
|
get lastNameControl(): AbstractControl {
|
||||||
|
return this.formGroup.get('lastName');
|
||||||
|
}
|
||||||
|
get ssnControl(): AbstractControl {
|
||||||
|
return this.formGroup.get('ssn');
|
||||||
|
}
|
||||||
|
get servicesControl(): AbstractControl {
|
||||||
|
return this.formGroup.get('services');
|
||||||
|
}
|
||||||
|
get authorizationsControl(): AbstractControl {
|
||||||
|
return this.formGroup.get('authorizations');
|
||||||
|
}
|
||||||
|
|
||||||
|
get formErrors(): { id: string; message: string }[] {
|
||||||
|
const controlsWithErrors = Object.keys(this.formGroup.controls).filter(
|
||||||
|
key => !!this.formGroup.controls[key].errors
|
||||||
|
);
|
||||||
|
|
||||||
|
return controlsWithErrors.map(key => ({
|
||||||
|
id: key,
|
||||||
|
message: this.formGroup.controls[key].errors.message,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _markFormAsDirty(): void {
|
||||||
|
Object.keys(this.formGroup.controls).forEach(control => {
|
||||||
|
this.formGroup.get(control).markAsDirty();
|
||||||
|
this.formGroup.get(control).markAsTouched();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleAuthorization(authorization: Authorization, checked: boolean): void {
|
||||||
|
const currentAuthorizations = this.authorizationsControl.value;
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
this.authorizationsControl.patchValue([...currentAuthorizations, authorization]);
|
||||||
|
} else {
|
||||||
|
this.authorizationsControl.patchValue(
|
||||||
|
currentAuthorizations.filter(currentAuthorization => currentAuthorization.id !== authorization.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
togglePendingService(service: Service, checked: boolean): void {
|
||||||
|
const currentPendingServices = this.pendingServices;
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
this._pendingServices$.next([...currentPendingServices, service]);
|
||||||
|
} else {
|
||||||
|
this._pendingServices$.next(currentPendingServices.filter(currentService => currentService.id !== service.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleAllPendingServices(services: Service[], checked: boolean): void {
|
||||||
|
this._pendingServices$.next(checked ? services : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPendingServices(): void {
|
||||||
|
this._pendingServices$.next([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
addPendingServicesToFormControl(): void {
|
||||||
|
this.servicesControl.patchValue(this.pendingServices);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeServiceFromFormControl(id: string): void {
|
||||||
|
const currentAddedServices = this.servicesControl.value;
|
||||||
|
|
||||||
|
this.servicesControl.patchValue(currentAddedServices.filter(currentService => currentService.id !== id));
|
||||||
|
}
|
||||||
|
|
||||||
|
setFocusOnInvalidInput(event: CustomEvent): void {
|
||||||
|
console.log(event.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetForm(event: Event): void {
|
||||||
|
event.preventDefault();
|
||||||
|
this.formGroup.reset({
|
||||||
|
firstName: '',
|
||||||
|
lastName: '',
|
||||||
|
ssn: '',
|
||||||
|
services: [],
|
||||||
|
authorizations: [],
|
||||||
|
});
|
||||||
|
// Object.keys(this.formGroup.controls).forEach(controlKey => this.formGroup.controls[controlKey].markAsPristine());
|
||||||
|
}
|
||||||
|
|
||||||
|
submitForm(): void {
|
||||||
|
this.submitted = true;
|
||||||
|
if (this.formGroup.valid) {
|
||||||
|
const submittableValues = {
|
||||||
|
...this.formGroup.value,
|
||||||
|
};
|
||||||
|
const post = this.employeeService.postNewEmployee(submittableValues).subscribe({
|
||||||
|
next: id => {
|
||||||
|
this.router.navigate(['/administration', 'personal', id]);
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
post.unsubscribe();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// this.formGroup.reset();
|
||||||
|
} else {
|
||||||
|
console.error('Form is invalid, do something...');
|
||||||
|
this._markFormAsDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +1,22 @@
|
|||||||
|
import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
|
||||||
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
|
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
|
||||||
import { DigiNgFormInputModule } from '@af/digi-ng/_form/form-input';
|
import { DigiNgFormInputModule } from '@af/digi-ng/_form/form-input';
|
||||||
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
import { DigiNgFormRadiobuttonGroupModule } from '@af/digi-ng/_form/form-radiobutton-group';
|
||||||
|
import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select';
|
||||||
|
import { DigiNgPopoverModule } from '@af/digi-ng/_popover/popover';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
|
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
|
||||||
import { CreateAccountComponent } from './create-account.component';
|
import { EmployeeFormComponent } from './employee-form.component';
|
||||||
import { DigiNgPopoverModule } from '@af/digi-ng/_popover/popover';
|
|
||||||
import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
|
|
||||||
import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
declarations: [CreateAccountComponent],
|
declarations: [EmployeeFormComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
RouterModule.forChild([{ path: '', component: CreateAccountComponent }]),
|
RouterModule.forChild([{ path: '', component: EmployeeFormComponent }]),
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
LocalDatePipeModule,
|
LocalDatePipeModule,
|
||||||
DigiNgFormInputModule,
|
DigiNgFormInputModule,
|
||||||
@@ -27,4 +27,4 @@ import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select';
|
|||||||
DigiNgFormCheckboxModule,
|
DigiNgFormCheckboxModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class CreateAccountModule {}
|
export class EmployeeFormModule {}
|
||||||
@@ -22,23 +22,37 @@
|
|||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" class="employees-list__column-head">
|
<th scope="col" class="employees-list__column-head">
|
||||||
<button class="employees-list__sort-button" (click)="handleSort('organization')">
|
<button class="employees-list__sort-button" (click)="handleSort('organizations')">
|
||||||
Utförandeverksamhet
|
Utförandeverksamheter
|
||||||
<ng-container *ngIf="sortBy?.key === 'organization'">
|
<ng-container *ngIf="sortBy?.key === 'organization'">
|
||||||
<digi-icon-caret-up class="employees-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
|
<digi-icon-caret-up class="employees-list__sort-icon" *ngIf="!sortBy.reverse"></digi-icon-caret-up>
|
||||||
<digi-icon-caret-down class="employees-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
|
<digi-icon-caret-down class="employees-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</button>
|
</button>
|
||||||
</th>
|
</th>
|
||||||
|
<th scope="col" class="employees-list__column-head">Redigera</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let employees of pagedEmployees">
|
<tr *ngFor="let employee of pagedEmployees">
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
<a [routerLink]="employees.id" class="employees-list__link">{{ employees.fullName }}</a>
|
<a [routerLink]="employee.id" class="employees-list__link">{{ employee.fullName }}</a>
|
||||||
</th>
|
</th>
|
||||||
<td>{{ employees.services.length ? employees.services.join(', ') : '-' }}</td>
|
<td>
|
||||||
<td>{{ employees.organization.address.city || '-' }}</td>
|
<ng-container *ngFor="let service of employee.services; let last = last">
|
||||||
|
{{ service.name }}<ng-container *ngIf="!last">, </ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ng-container *ngFor="let organization of employee.organizations; let last = last">
|
||||||
|
{{ organization.address.city }}<ng-container *ngIf="!last">, </ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<digi-button af-variation="tertiary">
|
||||||
|
<digi-icon-edit style="--digi--ui--width--icon: 1.25rem;" slot="icon"></digi-icon-edit>
|
||||||
|
</digi-button>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ export class EmployeesListComponent {
|
|||||||
private _currentPage$ = new BehaviorSubject<number>(1);
|
private _currentPage$ = new BehaviorSubject<number>(1);
|
||||||
private _employeesPerPage = 10;
|
private _employeesPerPage = 10;
|
||||||
|
|
||||||
private _searchValue$ = new BehaviorSubject<string>('');
|
|
||||||
|
|
||||||
get currentPage(): number {
|
get currentPage(): number {
|
||||||
return this._currentPage$.getValue();
|
return this._currentPage$.getValue();
|
||||||
}
|
}
|
||||||
|
|||||||
24
apps/dafa-web/src/app/services/api/authorizations.service.ts
Normal file
24
apps/dafa-web/src/app/services/api/authorizations.service.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from '@dafa-environment';
|
||||||
|
import {
|
||||||
|
Authorization,
|
||||||
|
AuthorizationApiResponse,
|
||||||
|
mapAuthorizationApiResponseToAuthorization,
|
||||||
|
} from '@dafa-models/authorization.model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
const API_HEADERS = { headers: environment.api.headers };
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class AuthorizationService {
|
||||||
|
private _authorizationsApiUrl = `${environment.api.url}/authorizations`;
|
||||||
|
public authorizations$: Observable<Authorization[]> = this.httpClient
|
||||||
|
.get<AuthorizationApiResponse[]>(this._authorizationsApiUrl, API_HEADERS)
|
||||||
|
.pipe(map(response => response.map(authorization => mapAuthorizationApiResponseToAuthorization(authorization))));
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient) {}
|
||||||
|
}
|
||||||
@@ -70,6 +70,8 @@ export class EmployeeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public postNewEmployee(employeeData: Employee): Observable<string> {
|
public postNewEmployee(employeeData: Employee): Observable<string> {
|
||||||
|
console.log(employeeData);
|
||||||
|
return;
|
||||||
return this.httpClient
|
return this.httpClient
|
||||||
.post<PegaEmployeeApiPostResponse>(
|
.post<PegaEmployeeApiPostResponse>(
|
||||||
this._employeeApiUrl,
|
this._employeeApiUrl,
|
||||||
|
|||||||
20
apps/dafa-web/src/app/services/api/service.service.ts
Normal file
20
apps/dafa-web/src/app/services/api/service.service.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { environment } from '@dafa-environment';
|
||||||
|
import { mapServiceApiResponseToService, Service, ServiceApiResponse } from '@dafa-models/service.model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
const API_HEADERS = { headers: environment.api.headers };
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ServiceService {
|
||||||
|
private _servicesApiUrl = `${environment.api.url}/services`;
|
||||||
|
public services$: Observable<Service[]> = this.httpClient
|
||||||
|
.get<ServiceApiResponse[]>(this._servicesApiUrl, API_HEADERS)
|
||||||
|
.pipe(map(response => response.map(service => mapServiceApiResponseToService(service))));
|
||||||
|
|
||||||
|
constructor(private httpClient: HttpClient) {}
|
||||||
|
}
|
||||||
@@ -3,8 +3,14 @@ import { ValidationError } from '@dafa-models/validation-error.model';
|
|||||||
|
|
||||||
export function RequiredValidator(label = 'Fältet'): ValidatorFn {
|
export function RequiredValidator(label = 'Fältet'): ValidatorFn {
|
||||||
return (control: AbstractControl): ValidationError => {
|
return (control: AbstractControl): ValidationError => {
|
||||||
if (control && !control.value) {
|
if (control) {
|
||||||
return { type: 'required', message: `${label} är obligatoriskt` };
|
if (!control.value) {
|
||||||
|
return { type: 'required', message: `${label} är obligatoriskt` };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(control.value) && !control.value.length) {
|
||||||
|
return { type: 'required', message: `Minst ${label} behöver väljas` };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.6 KiB |
@@ -3,6 +3,7 @@ export const environment = {
|
|||||||
api: {
|
api: {
|
||||||
meet: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/meettest/v1',
|
meet: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/meettest/v1',
|
||||||
default: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/v1/data',
|
default: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/v1/data',
|
||||||
|
url: '/api',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Basic dGVzdHVzZXIxOmRhZmFAMTIz', // user: testuser1, password: dafa@123
|
Authorization: 'Basic dGVzdHVzZXIxOmRhZmFAMTIz', // user: testuser1, password: dafa@123
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-weight: var(--digi--typography--font-weight);
|
font-weight: var(--digi--typography--font-weight);
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
|||||||
28
mock-api/dafa-web/scripts/authorizations.js
Normal file
28
mock-api/dafa-web/scripts/authorizations.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import faker from 'faker';
|
||||||
|
|
||||||
|
faker.locale = 'sv';
|
||||||
|
|
||||||
|
function generateAuthorizations() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: faker.datatype.uuid(),
|
||||||
|
name: 'Hantera behörigheter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: faker.datatype.uuid(),
|
||||||
|
name: 'Hantera användare',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: faker.datatype.uuid(),
|
||||||
|
name: 'Hantera organisation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: faker.datatype.uuid(),
|
||||||
|
name: 'Hantera ekonomi',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
generate: generateAuthorizations,
|
||||||
|
};
|
||||||
@@ -16,9 +16,7 @@ function generateCurrentUser() {
|
|||||||
min: 1000,
|
min: 1000,
|
||||||
max: 9999,
|
max: 9999,
|
||||||
})}`,
|
})}`,
|
||||||
phone: `07${faker.datatype.number(9)}-${faker.datatype.number({ min: 1000000, max: 9999999 })}`,
|
organizations: [ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)]],
|
||||||
email: faker.internet.email(),
|
|
||||||
organization: ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)],
|
|
||||||
authorizations: chooseRandom(AUTHORIZATIONS, faker.datatype.number(3)),
|
authorizations: chooseRandom(AUTHORIZATIONS, faker.datatype.number(3)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import faker from 'faker';
|
import faker from 'faker';
|
||||||
import kommuner from './kommuner.js';
|
import authorizations from './authorizations.js';
|
||||||
import languages from './languages.js';
|
|
||||||
import organizations from './organizations.js';
|
import organizations from './organizations.js';
|
||||||
import services from './services.js';
|
import services from './services.js';
|
||||||
|
|
||||||
faker.locale = 'sv';
|
faker.locale = 'sv';
|
||||||
|
|
||||||
const SERVICES = services.generate();
|
const SERVICES = services.generate();
|
||||||
const KOMMUN = kommuner.generate();
|
|
||||||
const ORGANIZATIONS = organizations.generate();
|
const ORGANIZATIONS = organizations.generate();
|
||||||
const STATUSES = [true, false];
|
|
||||||
const LANGUAGES = languages.generate();
|
|
||||||
const AUTHORIZATIONS = ['Hantera användare', 'Hantera origisation', 'Hantera ekonomi'];
|
|
||||||
|
|
||||||
function generateEmployees(amount = 10) {
|
function generateEmployees(amount = 10) {
|
||||||
const employees = [];
|
const employees = [];
|
||||||
@@ -27,24 +22,9 @@ function generateEmployees(amount = 10) {
|
|||||||
max: 9999,
|
max: 9999,
|
||||||
}
|
}
|
||||||
)}`,
|
)}`,
|
||||||
phone: `07${faker.datatype.number(9)}-${faker.datatype.number({ min: 1000000, max: 9999999 })}`,
|
organizations: [ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)]],
|
||||||
email: faker.internet.email(),
|
services: [SERVICES[Math.floor(Math.random() * SERVICES.length)]],
|
||||||
organization: ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)],
|
authorizations: authorizations.generate(),
|
||||||
services: [SERVICES[Math.floor(Math.random() * SERVICES.length)].name],
|
|
||||||
authorizations: AUTHORIZATIONS,
|
|
||||||
// active: STATUSES[Math.floor(Math.random() * STATUSES.length)],
|
|
||||||
// languages: [
|
|
||||||
// LANGUAGES.find(language => language.name === 'Svenska'),
|
|
||||||
// ...chooseRandom(LANGUAGES, faker.datatype.number(3)),
|
|
||||||
// ],
|
|
||||||
// outOfOffice: STATUSES[Math.floor(Math.random() * STATUSES.length)]
|
|
||||||
// ? [
|
|
||||||
// {
|
|
||||||
// start: new Date('2021-07-12'),
|
|
||||||
// end: new Date('2021-07-24'),
|
|
||||||
// },
|
|
||||||
// ]
|
|
||||||
// : [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
employees.push(person);
|
employees.push(person);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
import authorizations from './authorizations.js';
|
||||||
import currentUser from './current-user.js';
|
import currentUser from './current-user.js';
|
||||||
import employees from './employees.js';
|
import employees from './employees.js';
|
||||||
import kommuner from './kommuner.js';
|
import kommuner from './kommuner.js';
|
||||||
@@ -20,6 +21,7 @@ const apiData = {
|
|||||||
employeeId: generatedEmployees[Math.floor(Math.random() * generatedEmployees.length)].id,
|
employeeId: generatedEmployees[Math.floor(Math.random() * generatedEmployees.length)].id,
|
||||||
})),
|
})),
|
||||||
currentUser: currentUser.generate(),
|
currentUser: currentUser.generate(),
|
||||||
|
authorizations: authorizations.generate(),
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.writeFileSync('api.json', JSON.stringify(apiData, null, '\t'));
|
fs.writeFileSync('api.json', JSON.stringify(apiData, null, '\t'));
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
|
import faker from 'faker';
|
||||||
|
|
||||||
|
faker.locale = 'sv';
|
||||||
|
|
||||||
function generateServices() {
|
function generateServices() {
|
||||||
const services = [
|
const services = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: faker.datatype.uuid(),
|
||||||
name: 'KROM',
|
name: 'KROM',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: faker.datatype.uuid(),
|
||||||
name: 'KVL',
|
name: 'KVL',
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// id: 3,
|
// id: faker.datatype.uuid(),
|
||||||
// name: 'STOM',
|
// name: 'STOM',
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// id: 4,
|
// id: faker.datatype.uuid(),
|
||||||
// name: 'YSM',
|
// name: 'YSM',
|
||||||
// },
|
// },
|
||||||
// {
|
// {
|
||||||
// id: 5,
|
// id: faker.datatype.uuid(),
|
||||||
// name: 'AUB',
|
// name: 'AUB',
|
||||||
// },
|
// },
|
||||||
];
|
];
|
||||||
|
|||||||
Reference in New Issue
Block a user