src/app/child-dev-project/notes/model/note.ts
        
                        Properties | 
                
                        
  | 
                
                        Methods | 
                
                        
  | 
                
| attachment | 
                        Type :         string
                     | 
                
                        Decorators : 
                        
                            @DatabaseField({label: undefined, dataType: 'file'})
                     | 
                
| category | 
                        Type :         InteractionType
                     | 
                
                        Decorators : 
                        
                            @DatabaseField({label: undefined, dataType: 'configurable-enum', additional: INTERACTION_TYPE_CONFIG_ID, anonymize: 'retain'})
                     | 
                
| date | 
                        Type :         Date
                     | 
                
                        Decorators : 
                        
                            @DatabaseField({label: undefined, dataType: 'date-only', defaultValue: undefined, anonymize: 'retain'})
                     | 
                
| Static hasPII | 
                        Type :     unknown
                     | 
                
                        Default value : true
                     | 
                
| Static icon | 
                        Type :     IconName
                     | 
                
                        Default value : "file-alt"
                     | 
                
| Static label | 
                        Type :     unknown
                     | 
                
                        Default value : $localize`:label for entity:Note`
                     | 
                
| Static labelPlural | 
                        Type :     unknown
                     | 
                
                        Default value : $localize`:label (plural) for entity:Notes`
                     | 
                
| relatesTo | 
                        Type :         string
                     | 
                
                        Decorators : 
                        
                            @DatabaseField({anonymize: 'retain'})
                     | 
                
| 
                     id referencing a different entity (e.g. a recurring activity) this note is related to  | 
            
| 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'})
                     | 
                
| addChild | ||||||||
addChild(child: Entity | string)
                 | 
            ||||||||
| 
                         adds a new child to this note 
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            void
                         | 
            
| addSchool | ||||||||
addSchool(school: Entity | string)
                 | 
            ||||||||
| 
                         adds a new school to this note 
                                Parameters :
                                
                                 
                        
 
                            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 
                            Returns :      
                unknown
                         | 
            
| countWithStatus | ||||||||
countWithStatus(status: AttendanceLogicalStatus)
                 | 
            ||||||||
| 
                         Counts how many children have the given attendance status.
The status is counted based on the AttendanceLogicalStatus and the  
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            number
                        number of children with this status  | 
            
| Static create | ||||||||||||||||
                        
                    create(date: Date, subject: string, children: string[])
                 | 
            ||||||||||||||||
| 
                             
                                Parameters :
                                
                                 
                        
 
                            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 :
                                
                                 
                        
 
                            Returns :          
                            EventAttendance
                         | 
            
| Public getColor | 
                        
                    getColor()
                 | 
            
| 
                         
                            Returns :          
                any
                         | 
            
| Public getColorForId | ||||||
                        
                    getColorForId(childId: string)
                 | 
            ||||||
| 
                             
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            string
                         | 
            
| Static getPropertyFor | ||||||
                        
                    getPropertyFor(entityType: string)
                 | 
            ||||||
| 
                         Returns the name of the Note property where entities of the given entity type are stored 
                                Parameters :
                                
                                 
                        
 
                            Returns :      
                            "children" | "schools" | "authors" | "relatedEntities"
                         | 
            
| getWarningLevel | 
                        
                    getWarningLevel()
                 | 
            
| 
                         
                            Returns :          
                WarningLevel
                         | 
            
| hasUnknownAttendances | ||||||
hasUnknownAttendances(childId?: string)
                 | 
            ||||||
| 
                         Whether the attendance context information available through  While getAttendance will always set and return at least a default value  
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            boolean
                         | 
            
| removeChild | ||||||||
removeChild(childId: string)
                 | 
            ||||||||
| 
                         removes a specific child from this note 
                                Parameters :
                                
                                 
                        
 
                            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",
      config: { 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",
      config: { 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;
  }
}