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:
Erik Tiekstra
2021-06-01 11:19:22 +02:00
parent 4334fd7364
commit c4440a2bbe
41 changed files with 747 additions and 486 deletions

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"angular.enable-strict-mode-prompt": false
}

View File

@@ -13,5 +13,7 @@
></digi-ng-navigation-breadcrumbs>
<router-outlet></router-outlet>
</main>
<dafa-footer class="dafa__footer"></dafa-footer>
</div>
<dafa-toast-list></dafa-toast-list>

View File

@@ -3,22 +3,24 @@
@import 'variables/gutters';
.dafa {
width: 100vw;
height: 100vh;
overflow: hidden;
display: grid;
height: 100vh;
grid-template-columns: 15rem 1fr;
grid-template-rows: $dafa__navigation-height 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
'header header'
'sidebar content';
'sidebar content'
'footer footer';
@media (min-width: $digi--layout--breakpoint--m) {
grid-template-rows: $dafa__navigation-height-large 1fr;
}
// @media (min-width: $digi--layout--breakpoint--m) {
// grid-template-rows: $dafa__navigation-height-large 1fr auto;
// }
&__header {
grid-area: header;
position: sticky;
top: 0;
z-index: 1;
}
&__sidebar {
@@ -30,11 +32,16 @@
&__content {
grid-area: content;
padding: var(--digi--layout--gutter) $digi--layout--gutter--l $digi--layout--gutter--xxl;
overflow-y: auto;
}
&__breadcrumbs {
display: block;
margin-bottom: var(--digi--layout--gutter);
}
&__footer {
grid-area: footer;
background-color: var(--digi--ui--color--primary);
min-height: 10rem;
}
}

View File

@@ -7,6 +7,7 @@ import { CustomErrorHandler } from '@dafa-interceptors/custom-error-handler.modu
import { MarkdownModule } from 'ngx-markdown';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FooterModule } from './components/footer/footer.module';
import { NavigationModule } from './components/navigation/navigation.module';
import { SidebarModule } from './components/sidebar/sidebar.module';
import { SkipToContentModule } from './components/skip-to-content/skip-to-content.module';
@@ -23,6 +24,7 @@ import { ToastListModule } from './components/toast-list/toast-list.module';
NavigationModule,
SidebarModule,
ToastListModule,
FooterModule,
MarkdownModule.forRoot({ loader: HttpClient }),
DigiNgNavigationBreadcrumbsModule,
],

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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();
});
});

View File

@@ -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 {}

View 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 {}

View File

@@ -0,0 +1,7 @@
@media print {
.footer {
border-bottom-width: 0;
padding: var(--digi--layout--gutter) 0;
display: flex;
}
}

View File

@@ -1,11 +1,12 @@
@import 'variables/colors';
@import 'variables/navigation';
@import 'mixins/list';
.sidebar {
display: flex;
flex-direction: column;
position: sticky;
top: 0;
top: $dafa__navigation-height-large;
&__list {
@include dafa__reset-list;

View 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,
};
}

View File

@@ -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 { Service } from './service.model';
import { User, UserApiResponse } from './user.model';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Employee extends User {
languages: string[];
outOfOffice: {
start: Date;
end: Date;
}[];
participants: Participant[];
services: Service[];
active: boolean;
}
export interface EmployeeApiResponse extends UserApiResponse {
active: boolean;
services: Service[];
languages: string[];
participants: Participant[];
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface EmployeeApiRequestData extends Employee {}
export interface PegaEmployeesApiResponse {
pxMore: string;
pxObjClass: string;
@@ -44,7 +39,6 @@ export interface PegaEmployeeApiResponse {
pyOrganization: string;
pyOrgDivision: string;
pyOrgUnit: string;
pyTelephone: string;
pyUserIdentifier: string;
pyUserName: string;
}
@@ -52,7 +46,6 @@ export interface PegaEmployeeApiResponse {
export interface PegaEmployeeApiRequestData {
pyFirstName: string;
pyLastName: string;
pyTelephone: string;
}
export interface PegaEmployeeApiPostResponse {
@@ -61,15 +54,17 @@ export interface PegaEmployeeApiPostResponse {
pyFirstName: string;
pyHasError: 'true' | 'false';
pyLastName: string;
pyTelephone: string;
pyUserIdentifier: string;
}
export function mapEmployeeToEmployeeApiRequestData(data: Employee): PegaEmployeeApiRequestData {
export function mapEmployeeToEmployeeApiRequestData(data: Employee): EmployeeApiRequestData {
return data;
}
export function mapEmployeeToPegaEmployeeApiRequestData(data: Employee): PegaEmployeeApiRequestData {
return {
pyFirstName: data.firstName,
pyLastName: data.lastName,
pyTelephone: data.phone,
};
}
@@ -79,59 +74,41 @@ export function mapPegaEmployeeReponseToEmployee(data: PegaEmployeeApiResponse):
lastName: data.pyLastName,
firstName: data.pyFirstName,
fullName: `${data.pyFirstName} ${data.pyLastName}`,
organization: {
id: '',
name: data.pyOrganization,
kaNumber: null,
address: {
street: null,
houseNumber: null,
postalCode: null,
city: null,
kommun: null,
organizations: [
{
id: '',
name: data.pyOrganization,
kaNumber: null,
address: {
street: null,
houseNumber: null,
postalCode: null,
city: null,
kommun: null,
},
},
},
phone: data.pyTelephone,
email: '',
authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
],
authorizations: null,
// authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
services: [],
languages: [],
outOfOffice: null,
ssn: '',
participants: [],
active: true,
};
}
export function mapEmployeeReponseToEmployee(data: EmployeeApiResponse): Employee {
const {
id,
firstName,
lastName,
phone,
email,
ssn,
active,
services,
languages,
organization,
authorizations,
participants,
} = data;
const { id, firstName, lastName, ssn, services, languages, organizations, authorizations, participants } = data;
return {
id,
firstName,
lastName,
fullName: `${firstName} ${lastName}`,
organization,
phone,
email,
organizations,
authorizations,
services,
languages,
outOfOffice: null,
ssn,
participants,
active,
};
}

View 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,
};
}

View File

@@ -1,4 +1,4 @@
import { Authorization, mapPegaAuthorizationToAuthorization, PegaAuthorization } from '@dafa-enums/authorization.enum';
import { Authorization } from './authorization.model';
import { Organization } from './organization.model';
export interface User {
@@ -7,9 +7,7 @@ export interface User {
lastName: string;
fullName: string;
ssn: string;
phone: string;
email: string;
organization: Organization;
organizations: Organization[];
authorizations: Authorization[];
}
@@ -18,9 +16,7 @@ export interface UserApiResponse {
firstName: string;
lastName: string;
ssn: string;
phone: string;
email: string;
organization: Organization;
organizations: Organization[];
authorizations: Authorization[];
}
@@ -35,30 +31,20 @@ export interface PegaUserApiResponse {
pyOrganization: string;
pyOrgDivision: string;
pyOrgUnit: string;
pyTelephone: string;
pyUserIdentifier: string;
pyUserName: string;
pyAccessGroupsAdditional: string[];
pyAddresses: {
Email: {
pxObjClass: string;
pxSubscript: string;
pyEmailAddress: string;
};
};
}
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 {
id,
firstName,
lastName,
fullName: `${firstName} ${lastName}`,
ssn,
organization,
phone,
email,
organizations,
authorizations,
};
}
@@ -70,20 +56,21 @@ export function mapPegaUserApiReponseToUser(data: PegaUserApiResponse): User {
firstName: data.pyFirstName,
fullName: `${data.pyFirstName} ${data.pyLastName}`,
ssn: null,
organization: {
id: '',
name: data.pyOrganization,
kaNumber: null,
address: {
street: null,
houseNumber: null,
postalCode: null,
city: null,
kommun: null,
organizations: [
{
id: '',
name: data.pyOrganization,
kaNumber: null,
address: {
street: null,
houseNumber: null,
postalCode: null,
city: null,
kommun: null,
},
},
},
phone: data.pyTelephone,
email: data.pyAddresses.Email.pyEmailAddress,
authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
],
authorizations: null,
// authorizations: mapPegaAuthorizationToAuthorization(data.pyAccessGroup as PegaAuthorization),
};
}

View File

@@ -19,7 +19,11 @@ const routes: Routes = [
},
{
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),
},
];

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -7,76 +7,58 @@
perferendis commodi.
</p>
<div class="staff-card__contents">
<div class="staff-card__column">
<div class="employee-card__contents">
<div class="employee-card__column">
<h2>Kontaktuppgifter</h2>
<dl>
<dt>Namn</dt>
<dd *ngIf="detailedEmployeeData.fullName; else emptyDD">{{ detailedEmployeeData.fullName }}</dd>
<dt>Personnummer</dt>
<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>
</div>
<div class="staff-card__column">
<div class="employee-card__column">
<h2>Uppgifter om arbete</h2>
<dl>
<dt>Utförandeverksamhet</dt>
<dd *ngIf="detailedEmployeeData.organization; else emptyDD">
{{ detailedEmployeeData.organization.address.city }}
</dd>
<dt>Behörigheter</dt>
<dd *ngIf="detailedEmployeeData.authorizations?.length; else emptyDD">
{{ detailedEmployeeData.authorizations.join(', ') }}
</dd>
<dt>Frånvaroperiod</dt>
<ng-container *ngIf="detailedEmployeeData.outOfOffice?.length; else emptyDD">
<dd *ngFor="let date of detailedEmployeeData.outOfOffice">
{{ date.start | localDate }} - {{ date.end | localDate }}
</dd>
<ng-container *ngIf="detailedEmployeeData.authorizations.length; else emptyDD">
<dd *ngFor="let authorization of detailedEmployeeData.authorizations">{{ authorization.name }}</dd>
</ng-container>
<dt>Tjänster</dt>
<ng-container *ngIf="detailedEmployeeData.services.length; else emptyDD">
<dd *ngFor="let service of detailedEmployeeData.services">{{ service.name }}</dd>
</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>
</div>
<div class="staff-card__column">
<h2>Utförande verksamhet</h2>
<div class="employee-card__column">
<h2>Utförande verksamheter</h2>
<ul *ngIf="detailedEmployeeData.agencies?.length" class="staff-card__agencies">
<li *ngFor="let agency of detailedEmployeeData.agencies" class="staff-card__agency">
<h3>{{ agency.name }}</h3>
<ul *ngIf="detailedEmployeeData.organizations?.length" class="employee-card__organizations">
<li *ngFor="let organization of detailedEmployeeData.organizations" class="employee-card__organization">
<h3>{{ organization.name }}</h3>
<dl>
<dt>KA-nummer</dt>
<dd>{{ agency.kaNumber }}</dd>
<dd>{{ organization.kaNumber }}</dd>
<dt>Adress</dt>
<dd>{{ agency.address.street }} {{ agency.address.houseNumber }}</dd>
<dd>{{ agency.address.postalCode }} {{ agency.address.city }}</dd>
<dd>{{ organization.address.street }} {{ organization.address.houseNumber }}</dd>
<dd>{{ organization.address.postalCode }} {{ organization.address.city }}</dd>
</dl>
</li>
</ul>
</div>
<div class="staff-card__column">
<div class="employee-card__column">
<digi-ng-layout-expansion-panel>
<h3 style="margin-bottom: 0" data-slot-trigger>
Tilldelade deltagare ({{ detailedEmployeeData.participants?.length || 0 }})
</h3>
<ng-container *ngIf="detailedEmployeeData.participants?.length; else noParticipantsInfo">
<ul class="staff-card__participants">
<li *ngIf="detailedEmployeeData.participants.length > 1" class="staff-card__participant">
<ul class="employee-card__participants">
<li *ngIf="detailedEmployeeData.participants.length > 1" class="employee-card__participant">
<digi-form-checkbox
af-variation="primary"
af-label="Välj alla"
@@ -88,7 +70,7 @@
"
></digi-form-checkbox>
</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
af-variation="primary"
[afLabel]="participant.fullName"

View File

@@ -5,7 +5,7 @@
&__contents {
display: flex;
flex-direction: column;
gap: $digi--layout--gutter--l;
gap: $digi--layout--gutter--xl $digi--layout--gutter--l;
h2 {
margin-top: 0;
@@ -37,14 +37,14 @@
grid-column: 2;
}
&__agencies {
&__organizations {
@include dafa__reset-list;
display: flex;
flex-direction: column;
gap: 1rem;
}
&__agency {
&__organization {
border: 1px solid #333;
padding: var(--digi--layout--gutter);

View File

@@ -14,6 +14,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
})
export class EmployeeCardComponent extends UnsubscribeDirective {
detailedEmployeeData$: Observable<Employee>;
authorizationsAsString$: Observable<string>;
private _pendingSelectedParticipants$ = new BehaviorSubject<string[]>([]);
constructor(private activatedRoute: ActivatedRoute, private employeeService: EmployeeService) {

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -9,17 +9,17 @@ import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { CreateAccountComponent } from './create-account.component';
import { EmployeeFormComponent } from './employee-form.component';
describe('CreateAccountComponent', () => {
let component: CreateAccountComponent;
let fixture: ComponentFixture<CreateAccountComponent>;
describe('EmployeeFormComponent', () => {
let component: EmployeeFormComponent;
let fixture: ComponentFixture<EmployeeFormComponent>;
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [CreateAccountComponent],
declarations: [EmployeeFormComponent],
imports: [
RouterTestingModule,
HttpClientTestingModule,
@@ -36,7 +36,7 @@ describe('CreateAccountComponent', () => {
);
beforeEach(() => {
fixture = TestBed.createComponent(CreateAccountComponent);
fixture = TestBed.createComponent(EmployeeFormComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

View File

@@ -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();
}
}
}

View File

@@ -1,22 +1,22 @@
import { DigiNgFormCheckboxModule } from '@af/digi-ng/_form/form-checkbox';
import { DigiNgFormDatepickerModule } from '@af/digi-ng/_form/form-datepicker';
import { DigiNgFormInputModule } from '@af/digi-ng/_form/form-input';
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 { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { LocalDatePipeModule } from '@dafa-shared/pipes/local-date/local-date.module';
import { CreateAccountComponent } from './create-account.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';
import { EmployeeFormComponent } from './employee-form.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [CreateAccountComponent],
declarations: [EmployeeFormComponent],
imports: [
CommonModule,
RouterModule.forChild([{ path: '', component: CreateAccountComponent }]),
RouterModule.forChild([{ path: '', component: EmployeeFormComponent }]),
ReactiveFormsModule,
LocalDatePipeModule,
DigiNgFormInputModule,
@@ -27,4 +27,4 @@ import { DigiNgFormSelectModule } from '@af/digi-ng/_form/form-select';
DigiNgFormCheckboxModule,
],
})
export class CreateAccountModule {}
export class EmployeeFormModule {}

View File

@@ -22,23 +22,37 @@
</button>
</th>
<th scope="col" class="employees-list__column-head">
<button class="employees-list__sort-button" (click)="handleSort('organization')">
Utförandeverksamhet
<button class="employees-list__sort-button" (click)="handleSort('organizations')">
Utförandeverksamheter
<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-down class="employees-list__sort-icon" *ngIf="sortBy.reverse"></digi-icon-caret-down>
</ng-container>
</button>
</th>
<th scope="col" class="employees-list__column-head">Redigera</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let employees of pagedEmployees">
<tr *ngFor="let employee of pagedEmployees">
<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>
<td>{{ employees.services.length ? employees.services.join(', ') : '-' }}</td>
<td>{{ employees.organization.address.city || '-' }}</td>
<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>
</tbody>
</table>

View File

@@ -17,8 +17,6 @@ export class EmployeesListComponent {
private _currentPage$ = new BehaviorSubject<number>(1);
private _employeesPerPage = 10;
private _searchValue$ = new BehaviorSubject<string>('');
get currentPage(): number {
return this._currentPage$.getValue();
}

View 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) {}
}

View File

@@ -70,6 +70,8 @@ export class EmployeeService {
}
public postNewEmployee(employeeData: Employee): Observable<string> {
console.log(employeeData);
return;
return this.httpClient
.post<PegaEmployeeApiPostResponse>(
this._employeeApiUrl,

View 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) {}
}

View File

@@ -3,8 +3,14 @@ import { ValidationError } from '@dafa-models/validation-error.model';
export function RequiredValidator(label = 'Fältet'): ValidatorFn {
return (control: AbstractControl): ValidationError => {
if (control && !control.value) {
return { type: 'required', message: `${label} är obligatoriskt` };
if (control) {
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;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -3,6 +3,7 @@ export const environment = {
api: {
meet: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/meettest/v1',
default: 'https://dafa-utv.tocp.arbetsformedlingen.se/prweb/api/v1/data',
url: '/api',
headers: {
Authorization: 'Basic dGVzdHVzZXIxOmRhZmFAMTIz', // user: testuser1, password: dafa@123
},

View File

@@ -15,7 +15,6 @@
body {
margin: 0;
font-weight: var(--digi--typography--font-weight);
overflow: hidden;
}
button {

View 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,
};

View File

@@ -16,9 +16,7 @@ function generateCurrentUser() {
min: 1000,
max: 9999,
})}`,
phone: `07${faker.datatype.number(9)}-${faker.datatype.number({ min: 1000000, max: 9999999 })}`,
email: faker.internet.email(),
organization: ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)],
organizations: [ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)]],
authorizations: chooseRandom(AUTHORIZATIONS, faker.datatype.number(3)),
};
}

View File

@@ -1,17 +1,12 @@
import faker from 'faker';
import kommuner from './kommuner.js';
import languages from './languages.js';
import authorizations from './authorizations.js';
import organizations from './organizations.js';
import services from './services.js';
faker.locale = 'sv';
const SERVICES = services.generate();
const KOMMUN = kommuner.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) {
const employees = [];
@@ -27,24 +22,9 @@ function generateEmployees(amount = 10) {
max: 9999,
}
)}`,
phone: `07${faker.datatype.number(9)}-${faker.datatype.number({ min: 1000000, max: 9999999 })}`,
email: faker.internet.email(),
organization: ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)],
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'),
// },
// ]
// : [],
organizations: [ORGANIZATIONS[Math.floor(Math.random() * ORGANIZATIONS.length)]],
services: [SERVICES[Math.floor(Math.random() * SERVICES.length)]],
authorizations: authorizations.generate(),
};
employees.push(person);

View File

@@ -1,4 +1,5 @@
import fs from 'fs';
import authorizations from './authorizations.js';
import currentUser from './current-user.js';
import employees from './employees.js';
import kommuner from './kommuner.js';
@@ -20,6 +21,7 @@ const apiData = {
employeeId: generatedEmployees[Math.floor(Math.random() * generatedEmployees.length)].id,
})),
currentUser: currentUser.generate(),
authorizations: authorizations.generate(),
};
fs.writeFileSync('api.json', JSON.stringify(apiData, null, '\t'));

View File

@@ -1,23 +1,27 @@
import faker from 'faker';
faker.locale = 'sv';
function generateServices() {
const services = [
{
id: 1,
id: faker.datatype.uuid(),
name: 'KROM',
},
{
id: 2,
id: faker.datatype.uuid(),
name: 'KVL',
},
// {
// id: 3,
// id: faker.datatype.uuid(),
// name: 'STOM',
// },
// {
// id: 4,
// id: faker.datatype.uuid(),
// name: 'YSM',
// },
// {
// id: 5,
// id: faker.datatype.uuid(),
// name: 'AUB',
// },
];