src/app/features/attendance/analysis/attendance-details/attendance-details.component.ts

Description

Displays detailed attendance data for a calculated attendance time period (ActivityAttendance). This is often displayed as a dialog for drilling down into details.

Example

Metadata

Relationships

Used by

No results matching.

Depends on

Index

Properties
Methods
Inputs

Constructor

constructor()

Inputs

entity
Default value : this.data.attendance
forChild
Default value : this.data.forChild

Methods

showEventDetails
showEventDetails(event: Entity)
Parameters :
Name Type Optional
event Entity No
Returns : void

Properties

Readonly dataSource
Type : unknown
Default value : new InMemoryDataSource()
eventEntityType
Type : unknown
Default value : computed(() => this.entity()?.events[0]?.entity?.getConstructor(), )
eventsColumns
Type : FormFieldConfig[]
Default value : [ { id: "date" }, { id: "subject", label: $localize`Event` }, { id: "getAttendance", label: $localize`:How a child attended, e.g. too late, in time, excused, e.t.c:Attended`, viewComponent: "ReadonlyFunction", additional: (event: Entity) => { const eventWithAttendance = this.entity().events.find( (e) => e.entity === event, ); if (this.forChild()) { const item = eventWithAttendance?.getAttendanceForParticipant( this.forChild(), ); return item?.status?.label || "-"; } else { const avg = eventWithAttendance?.getAttendanceStats().average; if (!Number.isFinite(avg)) { return $localize`N/A`; } return `${(avg * 100).toFixed(0)}%`; } }, }, ]
import {
  ChangeDetectionStrategy,
  Component,
  computed,
  effect,
  inject,
  input,
} from "@angular/core";
import { ActivityAttendance } from "../../model/activity-attendance";
import { Entity } from "#src/app/core/entity/model/entity";
import { FormFieldConfig } from "#src/app/core/common-components/entity-form/FormConfig";
import { FormDialogService } from "#src/app/core/form-dialog/form-dialog.service";
import { DialogCloseComponent } from "#src/app/core/common-components/dialog-close/dialog-close.component";
import { MAT_DIALOG_DATA, MatDialogModule } from "@angular/material/dialog";
import { MatFormFieldModule } from "@angular/material/form-field";
import { PercentPipe } from "@angular/common";
import { CustomDatePipe } from "#src/app/core/basic-datatypes/date/custom-date.pipe";
import { FormsModule } from "@angular/forms";
import { MatInputModule } from "@angular/material/input";
import { AttendanceCalendarComponent } from "../attendance-calendar/attendance-calendar.component";
import { EntitiesTableComponent } from "#src/app/core/common-components/entities-table/entities-table.component";
import { InMemoryDataSource } from "#src/app/core/common-components/entities-table/data-source/in-memory-data-source";

/**
 * Displays detailed attendance data for a calculated attendance time period (`ActivityAttendance`).
 * This is often displayed as a dialog for drilling down into details.
 */
@Component({
  selector: "app-attendance-details",
  templateUrl: "./attendance-details.component.html",
  styleUrls: ["./attendance-details.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    DialogCloseComponent,
    MatDialogModule,
    MatFormFieldModule,
    PercentPipe,
    CustomDatePipe,
    FormsModule,
    MatInputModule,
    EntitiesTableComponent,
    AttendanceCalendarComponent,
  ],
})
export class AttendanceDetailsComponent {
  private formDialog = inject(FormDialogService);
  private data = inject<{
    forChild: string;
    attendance: ActivityAttendance;
  }>(MAT_DIALOG_DATA);
  readonly dataSource = new InMemoryDataSource();

  entity = input(this.data.attendance);
  forChild = input(this.data.forChild);

  eventEntityType = computed(() =>
    this.entity()?.events[0]?.entity?.getConstructor(),
  );

  eventsColumns: FormFieldConfig[] = [
    { id: "date" },
    { id: "subject", label: $localize`Event` },
    {
      id: "getAttendance",
      label: $localize`:How a child attended, e.g. too late, in time, excused, e.t.c:Attended`,
      viewComponent: "ReadonlyFunction",
      additional: (event: Entity) => {
        const eventWithAttendance = this.entity().events.find(
          (e) => e.entity === event,
        );
        if (this.forChild()) {
          const item = eventWithAttendance?.getAttendanceForParticipant(
            this.forChild(),
          );
          return item?.status?.label || "-";
        } else {
          const avg = eventWithAttendance?.getAttendanceStats().average;
          if (!Number.isFinite(avg)) {
            return $localize`N/A`;
          }
          return `${(avg * 100).toFixed(0)}%`;
        }
      },
    },
  ];

  constructor() {
    effect(() => {
      const events = this.entity()?.events.map((e) => e.entity);
      this.dataSource.allRecords.set(events);
    });
  }

  showEventDetails(event: Entity) {
    this.formDialog.openView(event);
  }
}
<h1 mat-dialog-title>
  <app-dialog-close mat-dialog-close></app-dialog-close>
  {{ entity()?.activity?.toString() }}:
  {{ entity().periodFrom | customDate: "shortDate" }} -
  {{ entity().periodTo | customDate: "shortDate" }}
</h1>

<div mat-dialog-content>
  <div class="summary w-{{ entity().getWarningLevel() }}">
    <span
      i18n="
        Attendance|Attendance of a child (in percent) or the average of the
        event (in percent)
      "
      >Attendance:</span
    >
    @let pct =
      forChild()
        ? entity()?.getAttendancePercentage(forChild())
        : entity()?.getAttendancePercentageAverage();
    @if (pct !== undefined) {
      {{ pct | percent: "1.0-0" }}
    } @else {
      -
    }
  </div>

  @if (forChild()) {
    <div class="flex-row flex-wrap gap-regular">
      <mat-form-field>
        <mat-label i18n="days present|How many days a child was present"
          >Days Present</mat-label
        >
        <input
          matInput
          type="number"
          [value]="entity().countEventsPresent(forChild())"
          readonly
        />
      </mat-form-field>
      <mat-form-field>
        <mat-label i18n="days absent|How many days a child was absent"
          >Days Absent</mat-label
        >
        <input
          matInput
          type="number"
          [value]="entity().countEventsAbsent(forChild())"
          readonly
        />
      </mat-form-field>
      <mat-form-field>
        <mat-label
          i18n="
            unknown status|How many days the presence or absence of a child is
            unknown
          "
          >Unknown Status</mat-label
        >
        <input
          matInput
          type="number"
          [value]="entity().countEventsWithUnknownStatus(forChild())"
          readonly
        />
      </mat-form-field>
    </div>
  } @else {
    <div class="flex-row flex-wrap gap-regular">
      <mat-form-field>
        <mat-label i18n="Total present|How many children were present"
          >Total Present</mat-label
        >
        <input
          matInput
          type="number"
          [value]="entity().countTotalPresent()"
          readonly
        />
      </mat-form-field>
      <mat-form-field>
        <mat-label i18n="Total absent|How many children were absent"
          >Total Absent</mat-label
        >
        <input
          matInput
          type="number"
          [value]="entity().countTotalAbsent()"
          readonly
        />
      </mat-form-field>
      <mat-form-field>
        <mat-label
          i18n="
            Total unknown|How many children have an unknown presence or absence
            status
          "
          >Total Unknown</mat-label
        >
        <input
          matInput
          type="number"
          [value]="entity().countEventsWithUnknownStatus()"
          readonly
        />
      </mat-form-field>
    </div>
  }

  @if (!!eventEntityType()) {
    <app-entities-table
      [entityType]="eventEntityType()"
      [recordsDataSource]="dataSource"
      [customColumns]="eventsColumns"
      clickMode="none"
      (entityClick)="showEventDetails($event)"
      [editable]="false"
    >
    </app-entities-table>

    <app-attendance-calendar
      [records]="entity().events"
      [highlightForChild]="forChild()"
      [activity]="entity().activity"
    ></app-attendance-calendar>
  }
</div>

./attendance-details.component.scss

@use "variables/sizes";

.summary {
  font-weight: bold;
  margin-bottom: sizes.$regular;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""