src/app/features/attendance/display-attendance/display-attendance.component.ts

Extends

ViewDirective< AttendanceItem[], any >

Metadata

Relationships

Index

Properties
Inputs

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

Properties

items
Type : unknown
Default value : computed(() => (this.value()?.length ? this.value() : []))
percentage
Type : unknown
Default value : 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
Type : unknown
Default value : 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; } })
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;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""