Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 0d1b0550

Přidáno uživatelem Václav Jirák před téměř 6 roky(ů)

Re #7263 Static view for employer initialized

Re #7263 Day picker component implemented

Re #7263 Day picker component modified

Re #7253 Off days component implemented

Re #7263 User approval component implemented

Re #7263 Minor changes

Re #7263 Free days approval component implemented

Re #7263 Free days renamed to Off days

Re #7263 Created simple menu with a service and mock data

Re #7263 Implemented routing for dashboard and employee list

Re #7263 Added simple page for employee route

Re #7263 Off days approval component modified

Re #7263 Days off info component modified

Re #7263 Oncoming days off component implemented

Re #7263 Employer dashboard component implemented

Re #7263 Basic employer's dashboard completed

Re #7263 Menu items correctly displayed when selected

Re #7263 Changed click behavior in menu list

Re #7263 Removed information about remaining sick days

Zobrazit rozdíly:

frontend/package.json
16 16
    "@angular/compiler": "~7.2.0",
17 17
    "@angular/core": "~7.2.0",
18 18
    "@angular/forms": "~7.2.0",
19
    "@angular/http": "latest",
19 20
    "@angular/platform-browser": "~7.2.0",
20 21
    "@angular/platform-browser-dynamic": "~7.2.0",
21 22
    "@angular/router": "~7.2.0",
23
    "@ng-bootstrap/ng-bootstrap": "^4.1.1",
24
    "angular-calendar": "^0.27.5",
25
    "angularx-flatpickr": "^6.1.0",
22 26
    "core-js": "^2.5.4",
27
    "date-fns": "^1.30.1",
28
    "flatpickr": "^4.5.7",
23 29
    "rxjs": "~6.3.3",
24 30
    "tslib": "^1.9.0",
25
    "zone.js": "~0.8.26",
26
    "@angular/http": "latest"
31
    "zone.js": "~0.8.26"
27 32
  },
28 33
  "devDependencies": {
29 34
    "@angular-devkit/build-angular": "~0.13.0",
frontend/src/app/app-routing.module.ts
1 1
import { NgModule } from '@angular/core';
2 2
import { Routes, RouterModule } from '@angular/router';
3
import {EmployeesListComponent} from './employees-list/employees-list.component';
4
import {DashboardComponent} from './dashboard/dashboard.component';
3 5

  
4
const routes: Routes = [];
6
const routes: Routes = [
7
  { path: 'employees', component: EmployeesListComponent },
8
  { path: 'dashboard', component: DashboardComponent },
9
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
10
];
5 11

  
6 12
@NgModule({
7 13
  imports: [RouterModule.forRoot(routes)],
frontend/src/app/app.component.html
1
<b>Post test: </b> {{ postTestResponse }} <br>
2
<b>Get test: </b> {{ getTestResponse }} <br>
3
<b>EN Hello world test: </b> {{ enHelloWorldResponse }} <br>
4
<b>CZ Hello world test: </b> {{ czHelloWorldResponse }} <br>
5
<b>Database test: </b> {{ databaseResponse }} <br>
6
<router-outlet></router-outlet>
1
<div class="container-fluid h-100">
2
  <div class="row header">
3
    <img class="logo" src="../assets/images/logo.png" />
4
    <div class="user-info">
5
      <img class="user-icon" src="../assets/images/default-user.png"/>
6
      <span class="user-name">Václav Jirák</span>
7
    </div>
8
  </div>
9
  <div class="row navigation-and-content">
10
    <div class="col-lg-2 navigation">
11
      <app-menu></app-menu>
12
    </div>
13
    <div class="col-lg-10">
14
      <router-outlet></router-outlet>
15
    </div>
16
  </div>
17
</div>
frontend/src/app/app.component.sass
1
.header
2
  height: 50px
3
  background-color: #3F425D
4
  padding-left: 10px
5

  
6
.user-info
7
  height: 100%
8
  margin-left: auto
9
  margin-right: 0
10

  
11
.user-icon
12
  width: 35px
13
  height: 35px
14
  border-radius: 20px
15

  
16
.user-name
17
  height: 50px
18
  line-height: 50px
19
  color: white
20
  margin-left: 10px
21
  margin-right: 10px
22

  
23
.navigation-and-content
24
  height: calc(100% - 50px)
25

  
26
  .content
27
    padding: 0
28

  
29
.navigation
30
  background-color: #2F313F
31
  margin: 0
32
  padding: 0
frontend/src/app/app.component.spec.ts
1
import { TestBed, async } from '@angular/core/testing';
2
import { RouterTestingModule } from '@angular/router/testing';
3
import { AppComponent } from './app.component';
4

  
5
describe('AppComponent', () => {
6
  beforeEach(async(() => {
7
    TestBed.configureTestingModule({
8
      imports: [
9
        RouterTestingModule
10
      ],
11
      declarations: [
12
        AppComponent
13
      ],
14
    }).compileComponents();
15
  }));
16

  
17
  it('should create the app', () => {
18
    const fixture = TestBed.createComponent(AppComponent);
19
    const app = fixture.debugElement.componentInstance;
20
    expect(app).toBeTruthy();
21
  });
22

  
23
  it(`should have as title 'ymanager-frontend'`, () => {
24
    const fixture = TestBed.createComponent(AppComponent);
25
    const app = fixture.debugElement.componentInstance;
26
    expect(app.title).toEqual('ymanager-frontend');
27
  });
28

  
29
  it('should render title in a h1 tag', () => {
30
    const fixture = TestBed.createComponent(AppComponent);
31
    fixture.detectChanges();
32
    const compiled = fixture.debugElement.nativeElement;
33
    expect(compiled.querySelector('h1').textContent).toContain('Welcome to ymanager-frontend!');
34
  });
35
});
frontend/src/app/app.component.ts
1
import { Component, OnInit } from '@angular/core';
2
import { HttpClient } from '@angular/common/http';
3
import { environment } from '../environments/environment';
1
import {Component, OnInit} from '@angular/core';
2
import { registerLocaleData } from '@angular/common';
3
import localeCs from '@angular/common/locales/cs';
4 4

  
5 5
@Component({
6 6
  selector: 'app-root',
......
8 8
  styleUrls: ['./app.component.sass']
9 9
})
10 10
export class AppComponent implements OnInit {
11
  getTestResponse;
12
  postTestResponse;
13
  enHelloWorldResponse;
14
  czHelloWorldResponse;
15
  databaseResponse;
16
  constructor(private httpClient: HttpClient) {}
17 11

  
18
  ngOnInit() {
19
    this.httpClient.get(environment.apiUrl + 'test', { responseType: 'text' })
20
      .subscribe(data => this.getTestResponse = data);
21

  
22
    this.httpClient.post(environment.apiUrl + 'test', {}, { responseType: 'text' })
23
      .subscribe(data => this.postTestResponse = data);
24

  
25
    this.httpClient.get(environment.apiUrl + 'hello', { responseType: 'text' })
26
      .subscribe(data => this.enHelloWorldResponse = data);
12
  constructor() {
13
    registerLocaleData(localeCs);
14
  }
27 15

  
28
    this.httpClient.get(environment.apiUrl + 'hello?lang=cz', { responseType: 'text' })
29
      .subscribe(data => this.czHelloWorldResponse = data);
16
  ngOnInit() {}
30 17

  
31
    this.httpClient.get(environment.apiUrl + 'database', { responseType: 'text' })
32
      .subscribe(data => this.databaseResponse = data);
33
  }
34 18
}
frontend/src/app/app.module.ts
3 3

  
4 4
import { AppRoutingModule } from './app-routing.module';
5 5
import { AppComponent } from './app.component';
6
import {HttpClientModule} from '@angular/common/http';
6
import { MenuComponent } from './menu/menu.component';
7
import { EmployeesListComponent } from './employees-list/employees-list.component';
8
import { DashboardModule } from './dashboard/dashboard.module';
7 9

  
8 10
@NgModule({
9 11
  declarations: [
10
    AppComponent
12
    AppComponent,
13
    MenuComponent,
14
    EmployeesListComponent
11 15
  ],
12 16
  imports: [
13 17
    BrowserModule,
14 18
    AppRoutingModule,
15
    HttpClientModule
19
    DashboardModule
16 20
  ],
17 21
  providers: [],
18 22
  bootstrap: [AppComponent]
frontend/src/app/dashboard/dashboard.component.html
1
<app-employer-dashboard></app-employer-dashboard>
frontend/src/app/dashboard/dashboard.component.ts
1
import { Component, OnInit } from '@angular/core';
2

  
3
@Component({
4
  selector: 'app-dashboard',
5
  templateUrl: './dashboard.component.html',
6
  styleUrls: ['./dashboard.component.sass']
7
})
8
export class DashboardComponent implements OnInit {
9

  
10
  constructor() { }
11

  
12
  ngOnInit() {
13
  }
14

  
15
}
frontend/src/app/dashboard/dashboard.module.ts
1
import {NgModule} from '@angular/core';
2
import {CommonModule} from '@angular/common';
3
import {EmployerDashboardModule} from './employer-dashboard/employer-dashboard.module';
4
import {DashboardComponent} from './dashboard.component';
5

  
6
@NgModule({
7
  declarations: [ DashboardComponent ],
8
  exports:      [ DashboardComponent ],
9
  imports: [
10
    EmployerDashboardModule
11
  ]
12
})
13
export class DashboardModule { }
frontend/src/app/dashboard/employer-dashboard/employer-dashboard.component.html
1
<div class="container-fluid h-100">
2
  <div class="row">
3
    <div class="col-lg-8 mid-panel">
4

  
5
      <div *ngIf="usersToApprove.length > 0" class="employer-dashboard-user-approval">
6
        <app-user-approval
7
          [usersToApprove]="usersToApprove"
8
          (userApprovedAction)="userApproved($event.user, $event.approved)"
9
        ></app-user-approval>
10
      </div>
11

  
12
      <div *ngIf="daysOffToApprove.length > 0" class="employer-dashboard-days-off-approval">
13
        <app-days-off-approval
14
          [daysOffToApprove]="daysOffToApprove"
15
          (daysOffApprovalAction)="daysOffApproved($event.daysOff, $event.approved)"
16
        ></app-days-off-approval>
17
      </div>
18

  
19
      <div *ngIf="oncomingDaysOff.length > 0" class="employer-dashboard-coming-days-off">
20
        <app-coming-days-off
21
          [oncomingDaysOff]="oncomingDaysOff"
22
          (daysOffRemovedAction)="daysOffRemoved($event.daysOff)"
23
        ></app-coming-days-off>
24
      </div>
25

  
26
      <div class="employer-dashboard-day-picker">
27
        <app-day-picker
28
          (selectedDate)="onDateSelect($event)"
29
        ></app-day-picker>
30
      </div>
31

  
32
    </div>
33

  
34
    <div class="col-lg-4 right-panel">
35

  
36
      <app-days-off-info
37
        [sickDaysRemaining]="5"
38
        [extraVacationRemaining]="10"
39
      ></app-days-off-info>
40

  
41
    </div>
42
  </div>
43
</div>
frontend/src/app/dashboard/employer-dashboard/employer-dashboard.component.sass
1
.row
2
  padding: 0
3

  
4
.mid-panel
5
  padding: 10px 0 0 10px
6

  
7
.right-panel
8
  padding: 10px 10px 0 10px
9

  
10
.employer-dashboard-user-approval
11
  padding: 0 0 10px 0
12

  
13
.employer-dashboard-days-off-approval
14
  padding: 0 0 10px 0
15

  
16
.employer-dashboard-coming-days-off
17
  padding: 0 0 10px 0
frontend/src/app/dashboard/employer-dashboard/employer-dashboard.component.ts
1
import { Component, OnInit } from '@angular/core';
2
import {UserToApprove} from '../../user-approval/user-to-approve.model';
3
import {DaysOff} from '../../shared/days-off.model';
4
import {OffDayType } from '../../shared/off-day-type';
5

  
6
@Component({
7
  selector: 'app-employer-dashboard',
8
  templateUrl: './employer-dashboard.component.html',
9
  styleUrls: ['./employer-dashboard.component.sass']
10
})
11
export class EmployerDashboardComponent implements OnInit {
12

  
13
  usersToApprove: UserToApprove[] = [
14
    { date: new Date(), email: 'kek@kek.cz', name: 'Václav Jirák' },
15
    { date: new Date(), email: 'kuadas@kek.cz', name: 'Věnceslav Kárij' }
16
  ];
17

  
18
  daysOffToApprove: DaysOff[] = [
19
    { username: 'Václav Jirák', dateFrom: new Date(2019, 10, 13), dateTo: new Date(), type: OffDayType.Sickday },
20
    { username: 'Václav Jirák', dateFrom: new Date(2019, 10, 1), dateTo: new Date(), type: OffDayType.ExtraVacation },
21
  ];
22

  
23
  daysOff: DaysOff[] = [
24
    {
25
      username: '',
26
      dateFrom: new Date(2019, 5, 5),
27
      dateTo: new Date(2019, 5, 6),
28
      type: OffDayType.ExtraVacation
29
    },
30
    {
31
      username: '',
32
      dateFrom: new Date(2019, 5, 8),
33
      dateTo: new Date(2019, 5, 8),
34
      type: OffDayType.Sickday
35
    },
36
    {
37
      username: '',
38
      dateFrom: new Date(2019, 3, 8),
39
      dateTo: new Date(2019, 3, 9),
40
      type: OffDayType.Sickday
41
    },
42
  ];
43

  
44
  oncomingDaysOff: DaysOff[] = [];
45

  
46
  constructor() { }
47

  
48
  ngOnInit() {
49
    this.oncomingDaysOff = this.calculateComingDaysOff();
50
  }
51

  
52
  onDateSelect( date: Date ) {
53
    console.log('Date selected: ' + date.toDateString());
54
  }
55

  
56
  userApproved( user: UserToApprove, approved: boolean ) {
57
    console.log(user.name + ' - approved: ' + approved);
58
    this.usersToApprove.splice(
59
      this.usersToApprove.indexOf(user), 1
60
    );
61
  }
62

  
63
  daysOffApproved(daysOff: DaysOff, approved: boolean ) {
64
    console.log(daysOff.username + ', ' + approved);
65
    this.daysOffToApprove.splice(
66
      this.daysOffToApprove.indexOf(daysOff), 1
67
    );
68
  }
69

  
70
  daysOffRemoved(daysOff: DaysOff) {
71
    this.daysOff.splice(
72
      this.daysOff.indexOf(daysOff), 1
73
    );
74
    this.oncomingDaysOff.splice(
75
      this.oncomingDaysOff.indexOf(daysOff), 1
76
    );
77
  }
78

  
79
  private calculateComingDaysOff(): DaysOff[] {
80
    let oncomingDaysOff: DaysOff[] = [];
81

  
82
    const today = new Date();
83
    this.daysOff.forEach((dayOff) => {
84
      if (dayOff.dateTo >= today) {
85
        oncomingDaysOff.push(dayOff);
86
      }
87
    });
88

  
89
    return oncomingDaysOff;
90
  }
91
}
frontend/src/app/dashboard/employer-dashboard/employer-dashboard.module.ts
1
import { NgModule } from '@angular/core';
2
import { CommonModule } from '@angular/common';
3
import { EmployerDashboardComponent } from './employer-dashboard.component';
4
import { DayPickerModule } from '../../day-picker/day-picker.module';
5
import { DaysOffInfoModule } from '../../days-off-info/days-off-info.module';
6
import { UserApprovalModule } from '../../user-approval/user-approval.module';
7
import { DaysOffApprovalModule } from '../../days-off-approval/days-off-approval.module';
8
import { OncomingDaysOffModule } from '../../oncoming-days-off/oncoming-days-off.module';
9

  
10
@NgModule({
11
  declarations: [ EmployerDashboardComponent ],
12
  exports:      [ EmployerDashboardComponent ],
13
  imports: [
14
    CommonModule,
15
    DayPickerModule,
16
    DaysOffInfoModule,
17
    UserApprovalModule,
18
    DaysOffApprovalModule,
19
    DayPickerModule,
20
    OncomingDaysOffModule
21
  ]
22
})
23
export class EmployerDashboardModule { }
frontend/src/app/day-picker/day-picker.component.html
1
<div class="day-picker-container">
2
  <div class="row text-center day-picker-month-selection">
3
    <div class="col-4"></div>
4
    <div class="col-1">
5
      <div class="btn btn-primary"
6
           mwlCalendarPreviousView
7
           [view]="view"
8
           [(viewDate)]="viewDate"
9
      >
10
        <
11
      </div>
12
    </div>
13
    <div class="col-2">
14
      <span id="day-picker-date">{{ viewDate | calendarDate:(view + 'ViewTitle'):locale }}</span>
15
    </div>
16
    <div class="col-1">
17
      <div class="btn btn-primary"
18
           mwlCalendarNextView
19
           [view]="view"
20
           [(viewDate)]="viewDate"
21
      >
22
        >
23
      </div>
24
      <div class="col-4"></div>
25
    </div>
26
  </div>
27

  
28
  <mwl-calendar-month-view
29
    [viewDate]="viewDate"
30
    (dayClicked)="dayClicked($event.day)"
31
    weekStartsOn="1"
32
    [locale]="locale"
33
  >
34
  </mwl-calendar-month-view>
35
</div>
frontend/src/app/day-picker/day-picker.component.sass
1
@import '../../common-styles/basic-component'
2

  
3
.day-picker-container
4
  @extend .basic-component
5

  
6
#day-picker-date
7
  font-weight: bold
8
  text-transform: uppercase
9

  
10
.day-picker-month-selection
11
  margin-bottom: 10px
frontend/src/app/day-picker/day-picker.component.ts
1
import { Component, ChangeDetectionStrategy, Output, EventEmitter } from '@angular/core';
2
import { CalendarView } from 'angular-calendar';
3

  
4
@Component({
5
  selector: 'app-day-picker',
6
  changeDetection: ChangeDetectionStrategy.OnPush,
7
  styleUrls: ['day-picker.component.sass'],
8
  templateUrl: 'day-picker.component.html'
9
})
10
export class DayPickerComponent {
11

  
12
  // TODO Move to language service
13
  locale = 'cs';
14

  
15
  // Type of calendar (constant)
16
  view: CalendarView = CalendarView.Month;
17

  
18
  // Selected date for this component's purpose
19
  private viewDate: Date = new Date();
20

  
21
  // EventEmitter informing about changes of selected date
22
  @Output() selectedDate = new EventEmitter<Date>();
23

  
24
  /**
25
   * Method that is invoked when user clicks on a day.
26
   * Sets selected date and emits event informing about new selected date.
27
   *
28
   * @param date Selected date
29
   */
30
  private dayClicked({ date }: { date: Date }): void {
31
    this.viewDate = date;
32
    this.selectedDate.emit(date);
33
  }
34
}
frontend/src/app/day-picker/day-picker.module.ts
1
import { NgModule } from '@angular/core';
2
import { CalendarModule, DateAdapter } from 'angular-calendar';
3
import { adapterFactory } from 'angular-calendar/date-adapters/date-fns';
4
import { DayPickerComponent } from './day-picker.component';
5
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
6

  
7
@NgModule({
8
  declarations: [ DayPickerComponent ],
9
  exports:      [ DayPickerComponent ],
10
  imports:      [
11
                  CalendarModule.forRoot({
12
                    provide: DateAdapter,
13
                    useFactory: adapterFactory
14
                  }),
15
                  BrowserAnimationsModule
16
                ],
17
})
18
export class DayPickerModule {}
frontend/src/app/days-off-approval/days-off-approval.component.html
1
<div class="days-off-approval-container">
2

  
3
  <div class="component-header">
4
    Schvalování volna
5
  </div>
6

  
7
  <div class="days-off-approval-list">
8
    <div class="row days-off-approval-header">
9
      <div class="col-md-3"> Jméno </div>
10
      <div class="col-md-3"> Typ volna </div>
11
      <div class="col-md-2"> Od </div>
12
      <div class="col-md-2"> Do </div>
13
      <div class="col-md-2"></div>
14
    </div>
15

  
16
    <div class="row days-off-approval" *ngFor="let daysOff of daysOffToApprove">
17
      <div class="col-md-3">
18
        {{daysOff.username}}
19
      </div>
20

  
21
      <div class="col-md-3">
22
        {{daysOffTypeToString(daysOff.type)}}
23
      </div>
24

  
25
      <div class="col-md-2">
26
        {{daysOff.dateFrom | date:'yyyy/MM/dd'}}
27
      </div>
28
      <div class="col-md-2">
29
        {{daysOff.dateTo | date:'yyyy/MM/dd'}}
30
      </div>
31
      <div class="col-md-2">
32
        <div class="btn btn-success approve-btn" (click)="daysOffApprovalCompleted(daysOff, true)">✓</div>
33
        <div class="btn btn-danger reject-btn"   (click)="daysOffApprovalCompleted(daysOff, false)">X</div>
34
      </div>
35
    </div>
36
  </div>
37

  
38
</div>
frontend/src/app/days-off-approval/days-off-approval.component.sass
1
@import '../../common-styles/basic-component'
2

  
3
.days-off-approval-container
4
  @extend .basic-component
5

  
6
  .days-off-approval-header
7
    padding: 10px
8
    margin: 0
9
    font-weight: bold
10

  
11
  .days-off-approval
12
    border-bottom: 1px solid gainsboro
13
    margin: 0
14
    padding: 10px
15
    line-height: 35px
16

  
17
    .approve-btn
18
      margin-right: 2px
frontend/src/app/days-off-approval/days-off-approval.component.ts
1
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2
import { DaysOff } from '../shared/days-off.model';
3
import { OffDayType } from '../shared/off-day-type';
4

  
5
@Component({
6
  selector: 'app-days-off-approval',
7
  templateUrl: './days-off-approval.component.html',
8
  styleUrls: ['./days-off-approval.component.sass']
9
})
10
export class DaysOffApprovalComponent implements OnInit {
11

  
12
  @Input()  daysOffToApprove: DaysOff[];
13
  @Output() daysOffApprovalAction = new EventEmitter<{daysOff: DaysOff, approved: boolean}>();
14

  
15
  constructor() { }
16

  
17
  ngOnInit() {
18
  }
19

  
20
  daysOffApprovalCompleted(daysOffApproved: DaysOff, isApproved: boolean ) {
21
    this.daysOffApprovalAction.emit({daysOff: daysOffApproved, approved: isApproved});
22
  }
23

  
24
  private daysOffTypeToString(taskType: OffDayType): string {
25
    switch (taskType) {
26
      case OffDayType.ExtraVacation:
27
        return 'Extra dovolená';
28
      case OffDayType.Sickday:
29
        return 'Sickdays';
30
    }
31
  }
32
}
frontend/src/app/days-off-approval/days-off-approval.module.ts
1
import { NgModule } from '@angular/core';
2
import { DaysOffApprovalComponent } from './days-off-approval.component';
3
import { BrowserModule } from '@angular/platform-browser';
4

  
5
@NgModule({
6
  declarations: [ DaysOffApprovalComponent ],
7
  exports:      [ DaysOffApprovalComponent ],
8
  imports:      [ BrowserModule ]
9
})
10
export class DaysOffApprovalModule { }
frontend/src/app/days-off-info/days-off-info.component.html
1
<div class="days-off-info-container">
2

  
3
  <div class="component-header">
4
    Zbývající volno
5
  </div>
6

  
7
  <div class="days-off-type-container">
8
    <span class="days-off-remaining">{{extraVacationRemaining}}</span>
9
    <span class="days-off-type">Extra dovolená</span>
10
  </div>
11

  
12
  <div class="days-off-type-container">
13
    <span class="days-off-remaining">{{sickDaysRemaining}}</span>
14
    <span class="days-off-type">Sickdays</span>
15
  </div>
16

  
17
</div>
frontend/src/app/days-off-info/days-off-info.component.sass
1
@import '../../common-styles/basic-component'
2

  
3
.days-off-info-container
4
  @extend .basic-component
5

  
6
.days-off-type-container
7
  border-bottom: 1px solid gainsboro
8
  padding-left: 20px
9

  
10
.days-off-remaining
11
  color: green
12
  font-size: 30px
13
  font-weight: bold
14

  
15
.days-off-type
16
  color: black
17
  font-weight: bold
18
  display: block
frontend/src/app/days-off-info/days-off-info.component.ts
1
import { Component, Input } from '@angular/core';
2

  
3
@Component({
4
  selector: 'app-days-off-info',
5
  templateUrl: './days-off-info.component.html',
6
  styleUrls: ['./days-off-info.component.sass']
7
})
8
export class DaysOffInfoComponent {
9

  
10
  @Input() sickDaysRemaining: number;
11

  
12
  @Input() extraVacationRemaining: number;
13

  
14
  constructor() { }
15
}
frontend/src/app/days-off-info/days-off-info.module.ts
1
import { NgModule } from '@angular/core';
2
import { DaysOffInfoComponent } from './days-off-info.component';
3

  
4
@NgModule({
5
  declarations: [ DaysOffInfoComponent ],
6
  exports:      [ DaysOffInfoComponent ]
7
})
8
export class DaysOffInfoModule { }
frontend/src/app/employees-list/employees-list.component.html
1
<div>
2
  <div>
3
    <h3>Zaměstnanci
4
      <span class="material-icons">add</span>
5
      <span class="material-icons">edit</span>
6
    </h3>
7

  
8
  </div>
9
  <hr>
10
</div>
frontend/src/app/employees-list/employees-list.component.sass
1
.material-icons
2
    display: inline-flex
3
    align-items: center
4
    justify-content: center
5
    vertical-align: middle
6

  
frontend/src/app/employees-list/employees-list.component.ts
1
import { Component, OnInit } from '@angular/core';
2

  
3
@Component({
4
  selector: 'app-employees-list',
5
  templateUrl: './employees-list.component.html',
6
  styleUrls: ['./employees-list.component.sass']
7
})
8
export class EmployeesListComponent implements OnInit {
9

  
10
  constructor() { }
11

  
12
  ngOnInit() {
13
  }
14

  
15
}
frontend/src/app/menu.service.ts
1
import { Injectable } from '@angular/core';
2
import { MenuItem } from './menu/menuItem';
3
import { Observable, of } from 'rxjs';
4
import { MENU_ITEMS } from './mock-menu-items';
5

  
6
@Injectable({
7
  providedIn: 'root'
8
})
9
export class MenuService {
10

  
11
  getMenuItems(): Observable<MenuItem[]> {
12
    return of(MENU_ITEMS);
13
  }
14

  
15
  constructor() { }
16
}
frontend/src/app/menu/menu.component.html
1
<div class="navigation">
2
  <nav class="navbar">
3
    <ul class="navbar-nav">
4
      <li *ngFor="let item of menuItems"
5
          [class.selected]="item === selectedMenuItem"
6
          (click)="onSelect(item)"
7
          class="nav-item">
8
        <a routerLink="{{item.routePath}}"><div>{{item.name}}</div></a>
9
      </li>
10
    </ul>
11
  </nav>
12
</div>
frontend/src/app/menu/menu.component.sass
1
.navbar
2
  width: 100%
3
  margin: 0
4
  padding: 0
5

  
6
.navbar-nav
7
  width: 100%
8

  
9
.nav-bar
10
  width: 100%
11

  
12
.nav-item
13
  height: 50px
14
  line-height: 50px
15
  width: 100%
16
  padding-left: 20px
17
  color: #404353
18
  background-color: #2F313F
19
  border-style: solid
20
  border-width: 0 0 1px 0
21
  border-color: #6D6F81
22

  
23
  &:hover
24
    background-color: #414356
25

  
26
  a
27
    color: #6D6F81
28
    width: 100%
29
    height: 100%
30

  
31

  
32
.nav-item.selected
33
  background-color: #63AA22
34

  
35
  a
36
    color: white
37

  
38
  &:hover
39
    background-color: #7ad129
40

  
41

  
frontend/src/app/menu/menu.component.ts
1
import { Component, OnInit } from '@angular/core';
2
import { MenuService } from '../menu.service';
3
import { MenuItem } from './menuItem';
4

  
5
@Component({
6
  selector: 'app-menu',
7
  templateUrl: './menu.component.html',
8
  styleUrls: ['./menu.component.sass']
9
})
10
export class MenuComponent implements OnInit {
11
  menuItems: MenuItem[];
12
  selectedMenuItem: MenuItem;
13

  
14

  
15
  getMenuItems(): void {
16
    this.menuService.getMenuItems()
17
      .subscribe(menuItems => this.menuItems = menuItems);
18
  }
19

  
20
  onSelect(menuItem: MenuItem): void {
21
    this.selectedMenuItem = menuItem;
22
  }
23

  
24
  constructor(private menuService: MenuService) { }
25

  
26
  ngOnInit() {
27
    this.getMenuItems();
28
  }
29

  
30

  
31
}
frontend/src/app/menu/menuItem.ts
1
export class MenuItem {
2
  name: string;
3
  routePath: string;
4
}
frontend/src/app/mock-menu-items.ts
1
import { MenuItem } from './menu/menuItem';
2

  
3
export const MENU_ITEMS: MenuItem[] = [
4
  {name: 'Dashboard', routePath: 'dashboard'},
5
  {name: 'Zaměstnanci', routePath: 'employees'},
6
];
frontend/src/app/oncoming-days-off/oncoming-days-off.component.html
1
<div class="oncoming-days-off-container">
2

  
3
  <div class="component-header">
4
    Mé nadcházející volno
5
  </div>
6

  
7
  <div class="tasks-list">
8
    <div class="row oncoming-days-off-header">
9
      <div class="col-md-6">
10
        Typ volna
11
      </div>
12

  
13
      <div class="col-md-2">
14
        Od
15
      </div>
16

  
17
      <div class="col-md-2">
18
        Do
19
      </div>
20

  
21
      <div class="col-md-2">
22
      </div>
23
    </div>
24

  
25
    <div class="row oncoming-days-off" *ngFor="let daysOff of oncomingDaysOff">
26
      <div class="col-md-6">
27
        {{offDayTypeToString(daysOff.type)}}
28
      </div>
29

  
30
      <div class="col-md-2">
31
        {{daysOff.dateFrom | date:'yyyy/MM/dd'}}
32
      </div>
33

  
34
      <div class="col-md-2">
35
        {{daysOff.dateTo | date:'yyyy/MM/dd'}}
36
      </div>
37

  
38
      <div class="col-md-2">
39
        <div class="btn btn-danger reject-btn" (click)="daysOffRemoved(daysOff)">X</div>
40
      </div>
41
    </div>
42
  </div>
43

  
44
</div>
frontend/src/app/oncoming-days-off/oncoming-days-off.component.sass
1
@import '../../common-styles/basic-component'
2

  
3
.oncoming-days-off-container
4
  @extend .basic-component
5

  
6
  .oncoming-days-off-header
7
    padding: 10px
8
    margin: 0
9
    font-weight: bold
10

  
11
  .oncoming-days-off
12
    border-bottom: 1px solid gainsboro
13
    margin: 0
14
    padding: 10px
15
    line-height: 35px
16

  
17
    .approve-btn
18
      margin-right: 2px
frontend/src/app/oncoming-days-off/oncoming-days-off.component.ts
1
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
2
import {DaysOff} from '../shared/days-off.model';
3
import {OffDayType} from '../shared/off-day-type';
4

  
5
@Component({
6
  selector: 'app-coming-days-off',
7
  templateUrl: './oncoming-days-off.component.html',
8
  styleUrls: ['./oncoming-days-off.component.sass']
9
})
10
export class OncomingDaysOffComponent implements OnInit {
11

  
12
  @Input()  oncomingDaysOff: DaysOff[];
13
  @Output() daysOffRemovedAction = new EventEmitter<{daysOff: DaysOff}>();
14

  
15
  constructor() { }
16

  
17
  ngOnInit() {
18
  }
19

  
20
  private daysOffRemoved( removedDaysOff: DaysOff ) {
21
    this.daysOffRemovedAction.emit( {daysOff: removedDaysOff } );
22
  }
23

  
24
  // TODO
25
  //  days-off-approval duplicate
26
  private offDayTypeToString(taskType: OffDayType): string {
27
    switch (taskType) {
28
      case OffDayType.ExtraVacation:
29
        return 'Extra dovolená';
30
      case OffDayType.Sickday:
31
        return 'Sickdays';
32
    }
33
  }
34
}
frontend/src/app/oncoming-days-off/oncoming-days-off.module.ts
1
import { NgModule } from '@angular/core';
2
import { OncomingDaysOffComponent } from './oncoming-days-off.component';
3
import { BrowserModule } from '@angular/platform-browser';
4

  
5
@NgModule({
6
  declarations: [ OncomingDaysOffComponent ],
7
  exports:      [ OncomingDaysOffComponent ],
8
  imports:      [ BrowserModule ],
9
})
10
export class OncomingDaysOffModule {}
frontend/src/app/shared/days-off.model.ts
1
import { OffDayType } from './off-day-type';
2

  
3
export class DaysOff {
4
  username: string;
5
  dateFrom: Date;
6
  dateTo: Date;
7
  type: OffDayType;
8
}
frontend/src/app/shared/off-day-type.ts
1
export enum OffDayType {
2
  ExtraVacation,
3
  Sickday
4
}
frontend/src/app/user-approval/user-approval.component.html
1
<div class="user-approval-container">
2

  
3
  <div class="component-header">
4
    Schvalování uživatelů
5
  </div>
6

  
7
  <div class="user-approval-list">
8
    <div class="row user-to-approve-container" *ngFor="let user of usersToApprove">
9
      <div class="col-md-4">
10
        {{user.name}}
11
      </div>
12
      <div class="col-md-4">
13
        {{user.email}}
14
      </div>
15
      <div class="col-md-2">
16
        {{user.date | date:'yyyy/MM/dd'}}
17
      </div>
18
      <div class="col-md-2">
19
        <div class="btn btn-success approve-user-btn" (click)="userApproved(user, true)">✓</div>
20
        <div class="btn btn-danger reject-user-btn"   (click)="userApproved(user, false)">X</div>
21
      </div>
22
    </div>
23
  </div>
24

  
25
</div>
frontend/src/app/user-approval/user-approval.component.sass
1
@import '../../common-styles/basic-component'
2

  
3
.user-approval-container
4
  @extend .basic-component
5

  
6
  .user-to-approve-container
7
    border-bottom: 1px solid gainsboro
8
    margin: 0
9
    padding: 10px
10
    line-height: 35px
11

  
12
    .approve-user-btn
13
      margin-right: 2px
frontend/src/app/user-approval/user-approval.component.ts
1
import { Component, EventEmitter, Input, Output } from '@angular/core';
2
import { UserToApprove } from './user-to-approve.model';
3

  
4

  
5
@Component({
6
  selector: 'app-user-approval',
7
  templateUrl: './user-approval.component.html',
8
  styleUrls: ['./user-approval.component.sass']
9
})
10
export class UserApprovalComponent {
11

  
12
  @Input()  usersToApprove: UserToApprove[];
13
  @Output() userApprovedAction = new EventEmitter<{user: UserToApprove, approved: boolean}>();
14

  
15
  constructor() { }
16

  
17
  userApproved(approvedUser: UserToApprove, isApproved: boolean) {
18
    this.userApprovedAction.emit({user: approvedUser, approved: isApproved});
19
  }
20

  
21
}
frontend/src/app/user-approval/user-approval.module.ts
1
import { NgModule } from '@angular/core';
2
import { UserApprovalComponent } from './user-approval.component';
3
import { BrowserModule } from '@angular/platform-browser';
4

  
5
@NgModule({
6
  declarations: [ UserApprovalComponent ],
7
  exports:      [ UserApprovalComponent ],
8
  imports:      [ BrowserModule ]
9
})
10
export class UserApprovalModule { }
frontend/src/app/user-approval/user-to-approve.model.ts
1
export class UserToApprove {
2
  name: string;
3
  email: string;
4
  date: Date;
5
}
frontend/src/common-styles/basic-component.sass
1
.basic-component
2
  background-color: white
3
  padding: 10px
4
  border: 1px solid gainsboro
5

  
6
  .component-header
7
    font-size: 15px
8
    border-bottom: 1px solid gainsboro
9
    padding: 0 0 10px 20px
10
    margin: 0 -10px 0 -10px
frontend/src/index.html
2 2
<html lang="en">
3 3
<head>
4 4
  <meta charset="utf-8">
5
  <title>YmanagerFrontend</title>
5
  <title>Ymanager</title>
6 6
  <base href="/">
7 7

  
8 8
  <meta name="viewport" content="width=device-width, initial-scale=1">
9

  
10
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
11
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
12
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
13

  
14
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
15
  <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
16
  <link href="https://unpkg.com/font-awesome@4.7.0/css/font-awesome.css" rel="stylesheet">
17
  <link href="https://unpkg.com/angular-calendar@0.27.5/css/angular-calendar.css" rel="stylesheet">
18
  <link href="https://unpkg.com/flatpickr@4.5.7/dist/flatpickr.css" rel="stylesheet">
9 19
  <link rel="icon" type="image/x-icon" href="favicon.ico">
10 20
</head>
11 21
<body>
frontend/src/styles.sass
1
/* You can add global styles to this file, and also import other style files */
1
*
2
  margin: 0
3
  padding: 0
4
  font-family: "Helvetica", serif
5
  font-size: 12px
6

  
7

  
8
a
9
  &:hover
10
    text-decoration: none
11

  
12

  
13
body, html
14
  height: 100%
15
  background-color: #F0FFFD

Také k dispozici: Unified diff