src/app/features/attendance/add-day-attendance/activity-card/activity-card.component.ts
Simple representation of an event in the context of setting up or selecting an event for a roll call.
| changeDetection | ChangeDetectionStrategy.OnPush |
| selector | app-activity-card |
| standalone | true |
| imports |
MatCardModule
FontAwesomeModule
CustomDatePipe
|
| styleUrls | ./activity-card.component.scss |
| templateUrl | ./activity-card.component.html |
MatCardModule
BorderHighlightDirective
FontAwesomeModule
CustomDatePipe
Properties |
|
Inputs |
| event | |
Type : EventWithAttendance
|
|
| Required : true | |
|
The event to be displayed. |
|
| recurring | |
Type : boolean
|
|
|
Whether the event or activity is displayed in the style of events generated from a generic recurring activity. If not explicitly defined, it is inferred from the entity's |
|
| Readonly attendance |
Type : unknown
|
Default value : computed<AttendanceItem[]>(
() => this.event().attendanceItems,
)
|
|
The attendance items for the current event. |
import {
ChangeDetectionStrategy,
Component,
computed,
input,
} from "@angular/core";
import { AttendanceItem } from "../../model/attendance-item";
import { EventWithAttendance } from "../../model/event-with-attendance";
import { MatCardModule } from "@angular/material/card";
import { BorderHighlightDirective } from "#src/app/core/common-components/border-highlight/border-highlight.directive";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { CustomDatePipe } from "#src/app/core/basic-datatypes/date/custom-date.pipe";
/**
* Simple representation of an event
* in the context of setting up or selecting an event for a roll call.
*/
@Component({
selector: "app-activity-card",
templateUrl: "./activity-card.component.html",
styleUrls: ["./activity-card.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
MatCardModule,
BorderHighlightDirective,
FontAwesomeModule,
CustomDatePipe,
],
})
export class ActivityCardComponent {
/**
* The event to be displayed.
*/
readonly event = input.required<EventWithAttendance>();
/**
* An optional extra entity field to display on the card (e.g. "category").
* The value's `label` property is shown if available, otherwise the raw value.
*/
readonly extraField = computed(() => this.event().extraField);
/**
* Whether the event or activity is displayed in the style of events generated from a generic recurring activity.
*
* If not explicitly defined, it is inferred from the entity's `relatesTo` reference to a RecurringActivity.
*/
readonly recurring = input<boolean>();
/** The attendance items for the current event. */
readonly attendance = computed<AttendanceItem[]>(
() => this.event().attendanceItems,
);
/** Whether this event is linked to a recurring activity. */
readonly isRecurring = computed(() => {
const explicit = this.recurring();
if (explicit !== undefined) {
return explicit;
}
return this.event().isActivityEvent;
});
/** Resolved display value of the extra field, if configured. */
readonly extraFieldValue = computed<string | undefined>(() => {
const field = this.extraField();
if (!field) {
return undefined;
}
const val = this.event().entity[field];
return val?.label ?? val;
});
readonly warningLevel = computed<"ok" | "warning" | "urgent">(() => {
const att = this.attendance();
const hasUnknown = att.some((a) => !a.status?.id);
if (!hasUnknown) {
return "ok";
}
return this.isRecurring() ? "warning" : "urgent";
});
}
<mat-card
appBorderHighlight
[borderClass]="'border-' + warningLevel()"
class="main-card"
>
<mat-card-header>
<mat-card-title>{{ event().entity.toString() }}</mat-card-title>
</mat-card-header>
<mat-card-content class="text-secondary">
<fa-icon icon="child"></fa-icon>
{{ attendance().length }}
<span i18n>participants</span>
@if (!isRecurring() && event().date) {
<span class="sep">/</span>
<fa-icon icon="calendar"></fa-icon>
{{ event().date | customDate: "shortDate" }}
}
@if (extraFieldValue()) {
<span class="sep">/</span>{{ extraFieldValue() }}
}
</mat-card-content>
</mat-card>
./activity-card.component.scss
@use "variables/colors";
.border-ok {
border-color: colors.$success !important;
}
.border-warning {
border-color: colors.$warn !important;
}
.border-urgent {
border-color: colors.$error !important;
}
.main-card {
max-width: 500px;
height: 100%;
box-sizing: border-box;
}
.card-title {
font-weight: bold;
}
.sep {
font-weight: 900;
color: colors.$disabled;
/* Add a whitespace before the separator */
&::before {
content: " ";
}
/* Add a whitespace before the separator */
&::after {
content: " ";
}
}