src/app/features/attendance/display-attendance/display-attendance.component.ts
ViewDirective<
AttendanceItem[],
any
>
| changeDetection | ChangeDetectionStrategy.OnPush |
| selector | app-display-attendance |
| standalone | true |
| imports | |
| styleUrls | ./display-attendance.component.scss |
| templateUrl | ./display-attendance.component.html |
No results matching.
Properties |
|
Inputs |
| config | |
Type : C
|
|
Default value : undefined
|
|
|
Inherited from
ViewDirective
|
|
| entity | |
Type : Entity
|
|
|
Inherited from
ViewDirective
|
|
| formFieldConfig | |
Type : FormFieldConfig
|
|
|
Inherited from
ViewDirective
|
|
| id | |
Type : string
|
|
|
Inherited from
ViewDirective
|
|
| tooltip | |
Type : string
|
|
|
Inherited from
ViewDirective
|
|
| value | |
Type : T
|
|
|
Inherited from
ViewDirective
|
|
| items |
Type : unknown
|
Default value : computed(() => (this.value()?.length ? this.value() : []))
|
| Readonly config |
Type : unknown
|
Default value : computed<C>(() => {
const ffc = this.formFieldConfig();
return ffc !== undefined ? (ffc.additional as C) : this._directConfig();
})
|
|
Inherited from
ViewDirective
|
| Readonly isPartiallyAnonymized |
Type : unknown
|
Default value : computed<boolean>(() => {
const entity = this.entity();
const id = this.id();
return (
(entity?.anonymized &&
entity?.getSchema()?.get(id)?.anonymize === "retain-anonymized") ??
false
);
})
|
|
Inherited from
ViewDirective
|
import { ChangeDetectionStrategy, Component, computed } from "@angular/core";
import { ViewDirective } from "#src/app/core/entity/default-datatype/view.directive";
import { DynamicComponent } from "#src/app/core/config/dynamic-components/dynamic-component.decorator";
import { AttendanceItem } from "../model/attendance-item";
import { AttendanceLogicalStatus } from "../model/attendance-status";
import { PercentPipe } from "@angular/common";
import { TemplateTooltipDirective } from "#src/app/core/common-components/template-tooltip/template-tooltip.directive";
import { WarningLevel } from "#src/app/child-dev-project/warning-level";
import { EntityBlockComponent } from "#src/app/core/basic-datatypes/entity/entity-block/entity-block.component";
import { AttendanceDayBlockComponent } from "../attendance-week-dashboard/attendance-day-block/attendance-day-block.component";
/** Thresholds for attendance percentage coloring. */
const THRESHOLD_URGENT = 0.6;
const THRESHOLD_WARNING = 0.8;
@DynamicComponent("DisplayAttendance")
@Component({
selector: "app-display-attendance",
templateUrl: "./display-attendance.component.html",
styleUrls: ["./display-attendance.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
PercentPipe,
TemplateTooltipDirective,
EntityBlockComponent,
AttendanceDayBlockComponent,
],
})
export class DisplayAttendanceComponent extends ViewDirective<
AttendanceItem[],
any
> {
items = computed(() => (this.value()?.length ? this.value() : []));
percentage = computed(() => {
let present = 0;
let absent = 0;
for (const item of this.items()) {
switch (item.status?.countAs) {
case AttendanceLogicalStatus.PRESENT:
present++;
break;
case AttendanceLogicalStatus.ABSENT:
absent++;
break;
}
}
const total = present + absent;
return total > 0 ? present / total : undefined;
});
warningClass = computed(() => {
const pct = this.percentage();
if (pct == null) {
return "";
}
if (pct < THRESHOLD_URGENT) {
return "w-" + WarningLevel.URGENT;
} else if (pct < THRESHOLD_WARNING) {
return "w-" + WarningLevel.WARNING;
} else {
return "w-" + WarningLevel.OK;
}
});
}
@if (items().length) {
<span [appTemplateTooltip]="tooltip">
@if (percentage() !== undefined) {
<span class="mat-elevation-z1 attendance-block {{ warningClass() }}">
{{ percentage() | percent: "1.0-0" }}
</span>
}
({{ items().length }} <span i18n>participants</span>)
</span>
<ng-template #tooltip>
<div class="attendance-tooltip">
<div class="margin-bottom-regular" i18n>
{{ percentage() | percent: "1.0-0" }} attendance
</div>
<div class="attendance-stats">
@for (item of items(); track item.participant) {
<div class="flex-row gap-regular">
<app-attendance-day-block
[attendance]="item"
></app-attendance-day-block>
<app-entity-block
class="flex-grow"
[entityId]="item.participant"
[linkDisabled]="true"
></app-entity-block>
</div>
}
</div>
</div>
</ng-template>
} @else {
<span>-</span>
}
./display-attendance.component.scss
.attendance-block {
display: inline-block;
text-align: center;
border-radius: 4px;
padding: 4px;
margin: 4px;
font-weight: 500;
white-space: nowrap;
/* ensure same width for all percentages */
min-width: 5ch;
}
.attendance-tooltip {
padding: 8px;
}
.attendance-stats {
display: flex;
flex-direction: column;
gap: 4px;
}