File

src/app/child-dev-project/notes/model/note.ts

Index

Properties
Methods

Properties

attachment
Type : string
Decorators :
@DatabaseField({label: undefined, dataType: 'file'})
authors
Type : string[]
Default value : []
Decorators :
@DatabaseField({label: undefined, dataType: 'entity', isArray: true, additional: 'User', defaultValue: undefined, anonymize: 'retain'})

IDs of users that authored this note

category
Type : InteractionType
Decorators :
@DatabaseField({label: undefined, dataType: 'configurable-enum', additional: INTERACTION_TYPE_CONFIG_ID, anonymize: 'retain'})
children
Type : string[]
Default value : []
Decorators :
@DatabaseField({label: undefined, dataType: 'entity', isArray: true, additional: 'Child', entityReferenceRole: 'composite', editComponent: 'EditAttendance', anonymize: 'retain'})

IDs of Child entities linked with this note

date
Type : Date
Decorators :
@DatabaseField({label: undefined, dataType: 'date-only', defaultValue: undefined, anonymize: 'retain'})
Static hasPII
Default value : true
Static icon
Type : IconName
Default value : "file-alt"
Static label
Default value : $localize`:label for entity:Note`
Static labelPlural
Default value : $localize`:label (plural) for entity:Notes`
relatedEntities
Type : string[]
Default value : []
Decorators :
@DatabaseField({dataType: 'entity', isArray: true, additional: undefined, anonymize: 'retain'})

other records (e.g. a recurring activity, group membership, ...) to which this note is related in some way, so that notes can be displayed linked to these entities.

This property saves ids including their entity type prefix.

relatesTo
Type : string
Decorators :
@DatabaseField({anonymize: 'retain'})

id referencing a different entity (e.g. a recurring activity) this note is related to

schools
Type : string[]
Default value : []
Decorators :
@DatabaseField({label: undefined, dataType: 'entity', isArray: true, additional: 'School', entityReferenceRole: 'composite', anonymize: 'retain'})

related school ids (e.g. to infer participants for event roll calls)

subject
Type : string
Decorators :
@DatabaseField({label: undefined})
text
Type : string
Decorators :
@DatabaseField({label: undefined, dataType: 'long-text'})
Static toStringAttributes
Type : []
Default value : ["subject"]
warningLevel
Type : Ordering.EnumValue
Decorators :
@DatabaseField({label: undefined, dataType: 'configurable-enum', additional: 'warning-levels', anonymize: 'retain'})

Methods

addChild
addChild(child: Entity | string)

adds a new child to this note

Parameters :
Name Type Optional Description
child Entity | string No

The child or the id of the child to add to the notes

Returns : void
addSchool
addSchool(school: Entity | string)

adds a new school to this note

Parameters :
Name Type Optional Description
school Entity | string No

The school or its id to be added to the note

Returns : void
copy
copy()

Performs a deep copy of the note copying all simple data (such as the date, author, e.t.c.) as well as copying the child-array

countWithStatus
countWithStatus(status: AttendanceLogicalStatus)

Counts how many children have the given attendance status. The status is counted based on the AttendanceLogicalStatus and the AttendanceStatusType.countAs attribute

Parameters :
Name Type Optional Description
status AttendanceLogicalStatus No

which should be counted

Returns : number

number of children with this status

Static create
create(date: Date, subject: string, children: string[])
Parameters :
Name Type Optional Default value
date Date No
subject string No ""
children string[] No []
Returns : Note
getAttendance
getAttendance(child: string | Entity)

Returns the event attendance details for the given child.

This method returns a default object that can be used and updated even if no attendance has been recorded yet. Returns undefined if the child is not added to this event/note instance.

Parameters :
Name Type Optional Description
child string | Entity No

: The child or the id of the child to look for

Returns : EventAttendance
Public getColor
getColor()
Returns : any
Public getColorForId
getColorForId(childId: string)
Parameters :
Name Type Optional
childId string No
Returns : string
Static getPropertyFor
getPropertyFor(entityType: string)

Returns the name of the Note property where entities of the given entity type are stored

Parameters :
Name Type Optional
entityType string No
Returns : "children" | "schools" | "authors" | "relatedEntities"
getWarningLevel
getWarningLevel()
Returns : WarningLevel
hasUnknownAttendances
hasUnknownAttendances(childId?: string)

Whether the attendance context information available through getAttendance is missing data for some children.

While getAttendance will always set and return at least a default value hasUnknownAttendances can be used to flag events with incomplete data.

Parameters :
Name Type Optional
childId string Yes
Returns : boolean
removeChild
removeChild(childId: string)

removes a specific child from this note

Parameters :
Name Type Optional Description
childId string No

The id of the child to exclude from the notes

Returns : void
import { DatabaseEntity } from "../../../core/entity/database-entity.decorator";
import { Entity } from "../../../core/entity/model/entity";
import { DatabaseField } from "../../../core/entity/database-field.decorator";
import {
  INTERACTION_TYPE_CONFIG_ID,
  InteractionType,
} from "./interaction-type.interface";
import {
  EventAttendance,
  EventAttendanceMap,
} from "../../attendance/model/event-attendance";
import {
  AttendanceLogicalStatus,
  NullAttendanceStatusType,
} from "../../attendance/model/attendance-status";
import { getWarningLevelColor, WarningLevel } from "../../warning-level";
import { Ordering } from "../../../core/basic-datatypes/configurable-enum/configurable-enum-ordering";
import { PLACEHOLDERS } from "../../../core/entity/schema/entity-schema-field";
import { IconName } from "@fortawesome/fontawesome-svg-core";

@DatabaseEntity("Note")
export class Note extends Entity {
  static override toStringAttributes = ["subject"];
  static override label = $localize`:label for entity:Note`;
  static override labelPlural = $localize`:label (plural) for entity:Notes`;
  static override icon: IconName = "file-alt";
  static override hasPII = true;

  static create(
    date: Date,
    subject: string = "",
    children: string[] = [],
  ): Note {
    const instance = new Note();
    instance.date = date;
    instance.subject = subject;
    for (const child of children) {
      instance.addChild(child);
    }
    return instance;
  }

  /**
   * Returns the name of the Note property where entities of the given entity type are stored
   * @param entityType
   */
  static getPropertyFor(entityType: string) {
    switch (entityType) {
      case "Child":
        return "children";
      case "School":
        return "schools";
      case "User":
        return "authors";
      default:
        return "relatedEntities";
    }
  }

  // TODO: remove these special properties (children, schools) and use relatedEntities instead once the attendance system is generalized (#1364)
  /** IDs of Child entities linked with this note */
  @DatabaseField({
    label: $localize`:Label for the participants field of a note:Participants`,
    dataType: "entity",
    isArray: true,
    additional: "Child",
    entityReferenceRole: "composite",
    editComponent: "EditAttendance",
    anonymize: "retain",
  })
  children: string[] = [];

  /**
   * optional additional information about attendance at this event for each of the linked children
   *
   * No direct access to change this property. Use the `.getAttendance()` method to have safe access.
   */
  @DatabaseField({ anonymize: "retain" })
  private childrenAttendance: EventAttendanceMap = new EventAttendanceMap();

  @DatabaseField({
    label: $localize`:Label for the date of a note:Date`,
    dataType: "date-only",
    defaultValue: {
      mode: "dynamic",
      value: PLACEHOLDERS.NOW,
    },
    anonymize: "retain",
  })
  date: Date;

  @DatabaseField({
    label: $localize`:Label for the subject of a note:Subject`,
  })
  subject: string;

  @DatabaseField({
    label: $localize`:Label for the actual notes of a note:Notes`,
    dataType: "long-text",
  })
  text: string;

  /** IDs of users that authored this note */
  @DatabaseField({
    label: $localize`:Label for the social worker(s) who created the note:Team involved`,
    dataType: "entity",
    isArray: true,
    additional: "User",
    defaultValue: {
      mode: "dynamic",
      value: PLACEHOLDERS.CURRENT_USER,
    },
    anonymize: "retain",
  })
  authors: string[] = [];

  @DatabaseField({
    label: $localize`:Label for the category of a note:Category`,
    dataType: "configurable-enum",
    additional: INTERACTION_TYPE_CONFIG_ID,
    anonymize: "retain",
  })
  category: InteractionType;

  @DatabaseField({
    label: $localize`Attachment`,
    dataType: "file",
  })
  attachment: string;

  /**
   * id referencing a different entity (e.g. a recurring activity) this note is related to
   */
  @DatabaseField({
    anonymize: "retain",
  })
  relatesTo: string;

  /**
   * other records (e.g. a recurring activity, group membership, ...) to which this note is related in some way,
   * so that notes can be displayed linked to these entities.
   *
   * This property saves ids including their entity type prefix.
   */
  @DatabaseField({
    dataType: "entity",
    isArray: true,
    // by default no additional relatedEntities can be linked apart from children and schools, overwrite this in config to display (e.g. additional: "ChildSchoolRelation")
    additional: undefined,
    anonymize: "retain",
  })
  relatedEntities: string[] = [];

  /**
   * related school ids (e.g. to infer participants for event roll calls)
   */
  @DatabaseField({
    label: $localize`:label for the linked schools:Groups`,
    dataType: "entity",
    isArray: true,
    additional: "School",
    entityReferenceRole: "composite",
    anonymize: "retain",
  })
  schools: string[] = [];

  @DatabaseField({
    label: $localize`:Status of a note:Status`,
    dataType: "configurable-enum",
    additional: "warning-levels",
    anonymize: "retain",
  })
  warningLevel: Ordering.EnumValue;

  override getWarningLevel(): WarningLevel {
    if (this.warningLevel) {
      return WarningLevel[this.warningLevel.id];
    } else {
      return WarningLevel.NONE;
    }
  }

  public override getColor() {
    const actualLevel = this.getWarningLevel();
    if (actualLevel === WarningLevel.OK || actualLevel === WarningLevel.NONE) {
      return this.category?.color;
    } else {
      return super.getColor();
    }
  }

  public getColorForId(childId: string): string {
    if (
      this.category?.isMeeting &&
      this.childrenAttendance.get(childId)?.status.countAs ===
        AttendanceLogicalStatus.ABSENT
    ) {
      // child is absent, highlight the entry
      return getWarningLevelColor(WarningLevel.URGENT);
    }
    return this.getColor();
  }

  /**
   * removes a specific child from this note
   * @param childId The id of the child to exclude from the notes
   */
  removeChild(childId: string) {
    this.children = this.children.filter((c) => c !== childId);
    this.childrenAttendance.delete(childId);
  }

  /**
   * adds a new child to this note
   * @param child The child or the id of the child to add to the notes
   */
  addChild(child: Entity | string) {
    const childId = typeof child === "string" ? child : child?.getId();
    if (!childId || this.children.includes(childId)) {
      return;
    }

    this.children = this.children.concat(childId);
  }

  /**
   * adds a new school to this note
   * @param school The school or its id to be added to the note
   */
  addSchool(school: Entity | string) {
    const schoolId = typeof school === "string" ? school : school.getId();
    if (this.schools.includes(schoolId)) {
      return;
    }

    this.schools = this.schools.concat(schoolId);
  }

  /**
   * Returns the event attendance details for the given child.
   *
   * This method returns a default object that can be used and updated even if no attendance has been recorded yet.
   * Returns undefined if the child is not added to this event/note instance.
   *
   * @param child: The child or the id of the child to look for
   */
  getAttendance(child: string | Entity): EventAttendance {
    const childId = typeof child === "string" ? child : child.getId();
    if (!this.children.includes(childId)) {
      return undefined;
    }

    let attendance = this.childrenAttendance.get(childId);
    if (!attendance) {
      attendance = new EventAttendance();
      this.childrenAttendance.set(childId, attendance);
    }
    if (!(attendance instanceof EventAttendance)) {
      attendance = Object.assign(new EventAttendance(), attendance);
    }
    return attendance;
  }

  /**
   * Whether the attendance context information available through `getAttendance` is missing data for some children.
   *
   * While getAttendance will always set and return at least a default value `hasUnknownAttendances` can be used
   * to flag events with incomplete data.
   */
  hasUnknownAttendances(childId?: string): boolean {
    if (childId) {
      return (
        this.getAttendance(childId).status.id === NullAttendanceStatusType.id
      );
    }

    if (this.childrenAttendance.size < this.children.length) {
      return true;
    } else {
      for (const v of this.childrenAttendance.values()) {
        if (v.status.id === NullAttendanceStatusType.id) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Counts how many children have the given attendance status.
   * The status is counted based on the AttendanceLogicalStatus and the `AttendanceStatusType.countAs` attribute
   * @param status which should be counted
   * @returns number of children with this status
   */
  countWithStatus(status: AttendanceLogicalStatus): number {
    const attendanceValues = this.childrenAttendance.values();
    return [...attendanceValues].filter(
      (attendance) => attendance.status.countAs === status,
    ).length;
  }

  /**
   * Performs a deep copy of the note copying all simple data
   * (such as the date, author, e.t.c.) as well as copying the
   * child-array
   */
  override copy(): this {
    const note = super.copy();
    note.children = [...this.children];
    note.schools = [...this.schools];
    note.relatedEntities = [...this.relatedEntities];
    note.authors = [...this.authors];
    note.childrenAttendance = new EventAttendanceMap();
    this.childrenAttendance.forEach((value, key) => {
      note.childrenAttendance.set(key, value.copy());
    });
    return note;
  }
}

results matching ""

    No results matching ""