File

apps/recallassess/recallassess-api/src/api/client/participant/dto/participant.dto.ts

Description

Per-course enrollment summary — one entry per learning_group_participant row for a participant. Used by the View Details dialog to render every course with its own stage pill, progress, and meta info.

stage carries the literal Prisma enum value (PENDING_INVITE, INVITED, ACCEPTED, PRE_BAT, E_LEARNING, POST_BAT, COMPLETED). Cancelled enrollments are excluded server-side and won't appear here.

Index

Properties

Properties

allocated_at
allocated_at: string
Type : string
course_name
course_name: string
Type : string
enrollment_id
enrollment_id: number
Type : number
last_active_at
last_active_at: string | null
Type : string | null
learning_group_id
learning_group_id: number
Type : number
progress
progress: number
Type : number
stage
stage: string
Type : string
import { Exclude, Expose, Transform, TransformationType } from "class-transformer";
import { getFullName, getStatus } from "../utils";

/**
 * Per-course enrollment summary — one entry per learning_group_participant row
 * for a participant. Used by the View Details dialog to render every course
 * with its own stage pill, progress, and meta info.
 *
 * `stage` carries the literal Prisma enum value (PENDING_INVITE, INVITED,
 * ACCEPTED, PRE_BAT, E_LEARNING, POST_BAT, COMPLETED). Cancelled enrollments
 * are excluded server-side and won't appear here.
 */
export interface CLParticipantEnrolledCourse {
  enrollment_id: number;
  learning_group_id: number;
  course_name: string;
  stage: string;
  progress: number;
  allocated_at: string;
  last_active_at: string | null;
}

@Exclude()
export class CLParticipantDto {
  @Expose()
  id!: number;

  /**
   * Only derive from DB row on PLAIN_TO_CLASS (plainToInstance). On CLASS_TO_PLAIN (HTTP serializer)
   * `obj` is this DTO instance, which has no first_name/last_name — re-running would yield "Unknown".
   */
  @Expose()
  @Transform(({ obj, value, type }) =>
    type === TransformationType.PLAIN_TO_CLASS ? getFullName(obj) : value,
  )
  full_name!: string;

  @Expose()
  email!: string;

  @Expose()
  department!: string;

  @Expose()
  @Transform(({ obj, value, type }) =>
    type === TransformationType.PLAIN_TO_CLASS ? getStatus(obj) : value,
  )
  status!: string;

  @Expose()
  last_active!: string;

  @Expose()
  progress!: number;

  @Expose()
  courses_completed!: number;

  @Expose()
  total_courses!: number;

  @Expose()
  current_course?: string;

  // Email subscription status (optional - only included when requested)
  @Expose()
  email_subscription_status?: {
    isUnsubscribed: boolean;
    unsubscribedAt: string | null;
    unsubscribedReason: string | null;
    resubscribedAt: string | null;
    resubscribeCount: number;
  };

  // === Invitation tracking fields — populated by the participants list service ===

  /**
   * Stage of the participant's MOST RECENTLY allocated course assignment.
   * One of: PENDING_INVITE, INVITED, ACCEPTED, PRE_BAT, E_LEARNING, POST_BAT, COMPLETED.
   * Drives the row's stage pill in the client portal directory.
   */
  @Expose()
  current_stage?: string;

  /**
   * True when the participant has set up a password (users.password_hash IS NOT NULL).
   * Distinguishes a brand-new INVITED user from a returning user whose new course
   * just sits at ACCEPTED awaiting course-acceptance.
   */
  @Expose()
  has_password?: boolean;

  /**
   * True when the most recently allocated course has reached e-Learning Done
   * (status >= E_LEARNING_COMPLETED on the backend's progress timeline).
   * Drives visibility of the "Allocate next course" menu item.
   */
  @Expose()
  eligible_for_next?: boolean;

  /**
   * All non-cancelled course enrollments for this participant. Populated for
   * the list endpoint so the frontend can render the per-course breakdown
   * inside the View Details dialog without an extra round-trip.
   */
  @Expose()
  enrolled_courses?: CLParticipantEnrolledCourse[];
}

results matching ""

    No results matching ""