Skip to content

Commit

Permalink
Add report absence form, refs #186
Browse files Browse the repository at this point in the history
  • Loading branch information
hupf committed Sep 21, 2020
1 parent 3d8d606 commit 4ccc485
Show file tree
Hide file tree
Showing 52 changed files with 1,369 additions and 200 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div
class="erz-container erz-container-padding-y"
class="erz-container erz-container-limited erz-container-padding-y"
*erzLet="{
confirmationStates: confirmationStates$ | async,
categories: activeCategories$ | async
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
[class.disabled]="data.selection.length === 0"
routerLink="/edit-absences/edit"
[queryParams]="{
returnparams: (state.queryParams$ | async)?.toString()
returnparams: (state.queryParamsString$ | async)
}"
>
<i class="material-icons">edit</i>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { isTruthy } from 'src/app/shared/utils/filter';
export class EditAbsencesListComponent
implements OnInit, AfterViewInit, OnDestroy {
filterFromParams$ = this.route.queryParams.pipe(map(createFilterFromParams));
profileReturnParams$ = this.state.queryParams$;
profileReturnParams$ = this.state.queryParamsString$;

private destroy$ = new Subject();

Expand Down
40 changes: 6 additions & 34 deletions src/app/edit-absences/services/edit-absences-state.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Injectable, Inject } from '@angular/core';
import { Location } from '@angular/common';
import { HttpParams } from '@angular/common/http';
import { Params } from '@angular/router';
import { combineLatest, Observable } from 'rxjs';
import { map, shareReplay, takeUntil } from 'rxjs/operators';

import { PresenceControlEntry } from 'src/app/presence-control/models/presence-control-entry.model';
import { DropDownItem } from 'src/app/shared/models/drop-down-item.model';
import { LessonPresence } from 'src/app/shared/models/lesson-presence.model';
import { PresenceType } from 'src/app/shared/models/presence-type.model';
Expand All @@ -15,14 +13,15 @@ import { LoadingService } from 'src/app/shared/services/loading-service';
import { PresenceTypesService } from 'src/app/shared/services/presence-types.service';
import { sortDropDownItemsByValue } from 'src/app/shared/utils/drop-down-items';
import { spread } from 'src/app/shared/utils/function';
import { buildHttpParamsFromAbsenceFilter } from 'src/app/shared/utils/absences-filter';
import { buildParamsFromAbsenceFilter } from 'src/app/shared/utils/absences-filter';
import {
PaginatedEntriesService,
PAGE_LOADING_CONTEXT,
} from 'src/app/shared/services/paginated-entries.service';
import { Paginated } from 'src/app/shared/utils/pagination';
import { SETTINGS, Settings } from 'src/app/settings';
import { IConfirmAbsencesService } from 'src/app/shared/tokens/confirm-absences-service';
import { buildPresenceControlEntries } from '../../shared/utils/presence-control-entries';

export interface EditAbsencesFilter {
student: Option<number>;
Expand Down Expand Up @@ -51,7 +50,7 @@ export class EditAbsencesStateService
this.entries$,
this.presenceTypes$,
this.absenceConfirmationStates$,
]).pipe(map(spread(getPresenceControlEntries)), shareReplay(1));
]).pipe(map(spread(buildPresenceControlEntries)), shareReplay(1));

selected: ReadonlyArray<{
lessonIds: ReadonlyArray<number>;
Expand All @@ -68,7 +67,7 @@ export class EditAbsencesStateService
) {
super(location, loadingService, settings, '/edit-absences');

this.queryParams$
this.queryParamsString$
.pipe(takeUntil(this.destroy$))
.subscribe(
(returnparams) => (this.confirmBackLinkParams = { returnparams })
Expand Down Expand Up @@ -123,10 +122,8 @@ export class EditAbsencesStateService
);
}

protected buildHttpParamsFromFilter(
filterValue: EditAbsencesFilter
): HttpParams {
return buildHttpParamsFromAbsenceFilter(filterValue);
protected buildParamsFromFilter(filterValue: EditAbsencesFilter): Params {
return buildParamsFromAbsenceFilter(filterValue);
}

private loadPresenceTypes(): Observable<ReadonlyArray<PresenceType>> {
Expand All @@ -143,28 +140,3 @@ export class EditAbsencesStateService
);
}
}

function getPresenceControlEntries(
lessonPresences: ReadonlyArray<LessonPresence>,
presenceTypes: ReadonlyArray<PresenceType>,
confirmationStates: ReadonlyArray<DropDownItem>
): ReadonlyArray<PresenceControlEntry> {
return lessonPresences.map((lessonPresence) => {
let presenceType = null;
if (lessonPresence.TypeRef.Id) {
presenceType =
presenceTypes.find((t) => t.Id === lessonPresence.TypeRef.Id) || null;
}
let confirmationState;
if (lessonPresence.ConfirmationStateId) {
confirmationState = confirmationStates.find(
(s) => s.Key === lessonPresence.ConfirmationStateId
);
}
return new PresenceControlEntry(
lessonPresence,
presenceType,
confirmationState
);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class EvaluateAbsencesListComponent implements OnInit, AfterViewInit {
];

filterFromParams$ = this.route.queryParams.pipe(map(createFilterFromParams));
profileReturnParams$ = this.state.queryParams$;
profileReturnParams$ = this.state.queryParamsString$;

constructor(
public state: EvaluateAbsencesStateService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { takeUntil } from 'rxjs/operators';
import { LessonPresencesRestService } from 'src/app/shared/services/lesson-presences-rest.service';
import { LoadingService } from 'src/app/shared/services/loading-service';
import { LessonPresenceStatistic } from 'src/app/shared/models/lesson-presence-statistic';
import { buildHttpParamsFromAbsenceFilter } from 'src/app/shared/utils/absences-filter';
import { buildParamsFromAbsenceFilter } from 'src/app/shared/utils/absences-filter';
import { Paginated } from 'src/app/shared/utils/pagination';
import {
PaginatedEntriesService,
Expand Down Expand Up @@ -41,7 +41,7 @@ export class EvaluateAbsencesStateService
) {
super(location, loadingService, settings, '/evaluate-absences');

this.queryParams$
this.queryParamsString$
.pipe(takeUntil(this.destroy$))
.subscribe(
(returnparams) => (this.confirmBackLinkParams = { returnparams })
Expand Down Expand Up @@ -82,9 +82,7 @@ export class EvaluateAbsencesStateService
);
}

protected buildHttpParamsFromFilter(
filterValue: EvaluateAbsencesFilter
): HttpParams {
return buildHttpParamsFromAbsenceFilter(filterValue);
protected buildParamsFromFilter(filterValue: EvaluateAbsencesFilter): Params {
return buildParamsFromAbsenceFilter(filterValue);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="erz-container erz-container-padding-y">
<div class="erz-container erz-container-limited erz-container-padding-y">
<div
class="mb-3 pb-3 border-bottom"
*erzLet="(selectionService.selection$ | async)?.length as selectedCount"
*erzLet="getSelectedCount() | async as selectedCount"
>
{{
(selectedCount === 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { OnInit, Component, OnDestroy } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
import {
finalize,
map,
filter,
startWith,
switchMap,
take,
pluck,
} from 'rxjs/operators';

import { LessonPresencesUpdateRestService } from 'src/app/shared/services/lesson-presences-update-rest.service';
import { PresenceTypesService } from 'src/app/shared/services/presence-types.service';
import { getValidationErrors } from 'src/app/shared/utils/form';
import { Settings } from 'src/app/settings';
import { StorageService } from 'src/app/shared/services/storage.service';
import { PresenceType } from 'src/app/shared/models/presence-type.model';
import { isEmptyArray } from 'src/app/shared/utils/array';

@Component({
template: '',
})
export abstract class MyAbsencesAbstractConfirmComponent
implements OnInit, OnDestroy {
formGroup = this.createFormGroup();

saving$ = new BehaviorSubject(false);
protected submitted$ = new BehaviorSubject(false);

abstract absenceTypes$: Observable<ReadonlyArray<PresenceType>>;

absenceTypeIdErrors$ = combineLatest([
getValidationErrors(this.formGroup.get('absenceTypeId')),
this.submitted$,
]).pipe(
filter((v) => v[1]),
map((v) => v[0]),
startWith([])
);

abstract selectedLessonIds$: Observable<ReadonlyArray<number>>;
protected abstract confirmationStateId: Option<number> = null;

protected destroy$ = new Subject();

constructor(
protected fb: FormBuilder,
protected router: Router,
protected toastr: ToastrService,
protected translate: TranslateService,
protected presenceTypesService: PresenceTypesService,
protected updateService: LessonPresencesUpdateRestService,
protected storageService: StorageService,
protected settings: Settings
) {}

ngOnInit(): void {
// Nothing to confirm if no entries are selected
this.selectedLessonIds$
.pipe(take(1), filter(isEmptyArray))
.subscribe(() => this.navigateBack());
}

ngOnDestroy(): void {
this.destroy$.next();
}

onSubmit(): void {
this.submitted$.next(true);
if (this.formGroup.valid) {
const { absenceTypeId } = this.formGroup.value;
this.save(absenceTypeId);
}
}

cancel(): void {
this.navigateBack();
}

getSelectedCount(): Observable<number> {
return this.selectedLessonIds$.pipe(pluck('length'));
}

protected createFormGroup(): FormGroup {
return this.fb.group({
absenceTypeId: [null, Validators.required],
});
}

protected save(absenceTypeId: number): void {
this.saving$.next(true);

this.selectedLessonIds$
.pipe(
take(1),
switchMap((selectedLessonIds) =>
this.updateService.editLessonPresences(
selectedLessonIds,
[Number(this.storageService.getPayload()?.id_person)],
absenceTypeId,
this.confirmationStateId
)
),
finalize(() => this.saving$.next(false))
)
.subscribe(this.onSaveSuccess.bind(this));
}

protected onSaveSuccess(): void {
this.toastr.success(
this.translate.instant('my-absences.confirm.save-success')
);
this.navigateBack();
}

protected abstract navigateBack(): void;
}
Loading

0 comments on commit 4ccc485

Please sign in to comment.