File

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

Prefix

api/client/participant

Index

Methods

Methods

Async addParticipant
addParticipant(data: AddParticipantDto, auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.CREATED)
@Public()
@Post()
@ApiOperation({summary: 'Add a new participant'})
@ApiResponse({status: 201, description: 'Participant added successfully', type: CLParticipantDto})
@ApiResponse({status: 409, description: 'A contact with this email already exists'})

Add a new participant POST /api/client/participant

Parameters :
Name Type Optional
data AddParticipantDto No
auth CLAuthData No
Async checkParticipantActiveWork
checkParticipantActiveWork(id: number, auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.OK)
@Public()
@Get(':id/active-work')
@ApiOperation({summary: 'Check if participant has active work', description: 'Returns information about incomplete courses and pending assessments'})
@ApiResponse({status: 200, description: 'Returns active work information', type: ParticipantActiveWorkDto})
@ApiResponse({status: 400, description: 'Participant not found'})

Check participant active work before deactivation GET /api/client/participant/:id/active-work

Parameters :
Name Type Optional
id number No
auth CLAuthData No
Async deleteParticipant
deleteParticipant(id: number, auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.NO_CONTENT)
@Public()
@Delete(':id')
@ApiOperation({summary: 'Delete a participant contact'})
@ApiResponse({status: 204, description: 'Participant deleted successfully'})
@ApiResponse({status: 403, description: 'Forbidden — not a participant administrator'})
@ApiResponse({status: 422, description: 'Contact has an active course allocation and cannot be deleted'})

Delete a company contact. Participant administrator only; blocked when an active course allocation exists. DELETE /api/client/participant/:id

Parameters :
Name Type Optional
id number No
auth CLAuthData No
Returns : Promise<void>
Async getAllParticipants
getAllParticipants(query: ParticipantQueryDto, auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.OK)
@Public()
@Get()
@ApiOperation({summary: 'Get all participants with pagination, search and filters', description: 'Returns paginated participants filtered by search query, status, and participant group with metadata'})
@ApiResponse({status: 200, description: 'Returns paginated list of participants with metadata (page, limit, totalCount, totalPages, etc.)'})

Get all participants for client consumption with optional filtering and pagination GET /api/client/participant?page=1&limit=20&sq=john&status=active&participantGroup=Sales

Parameters :
Name Type Optional
query ParticipantQueryDto No
auth CLAuthData No
Async getLicenseAvailability
getLicenseAvailability(auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.OK)
@Public()
@Get('license-availability')
@ApiOperation({summary: 'Get license availability information'})
@ApiResponse({status: 200, description: 'Returns license availability information'})

Get license availability for adding participants GET /api/client/participant/license-availability

Parameters :
Name Type Optional
auth CLAuthData No
Returns : Promise<literal type>
Async getParticipantAdmin
getParticipantAdmin(auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.OK)
@Public()
@Get('admin')
@ApiOperation({summary: 'Get the current participant's administrator', description: 'Returns the Participant Administrator (User) who manages this participant for license allocation'})
@ApiResponse({status: 200, description: 'Returns the participant administrator's contact information'})
@ApiResponse({status: 404, description: 'Participant not found or no administrator assigned'})

Get the current participant's administrator GET /api/client/participant/admin

Parameters :
Name Type Optional
auth CLAuthData No
Returns : Promise<literal type | null>
Async getParticipantById
getParticipantById(id: number, auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.OK)
@Public()
@Get(':id')
@ApiOperation({summary: 'Get a participant by ID'})
@ApiResponse({status: 200, description: 'Returns a single participant with enriched data', type: CLParticipantDto})
@ApiResponse({status: 404, description: 'Participant not found'})

Get a single participant by ID GET /api/client/participant/:id

Parameters :
Name Type Optional
id number No
auth CLAuthData No
Async saveParticipant
saveParticipant(id: number, data: SaveParticipantDto, auth: CLAuthData)
Decorators :
@HttpCode(HttpStatus.OK)
@Public()
@Put(':id')
@ApiOperation({summary: 'Save a participant'})
@ApiResponse({status: 200, description: 'Participant saved successfully', type: CLParticipantDto})
@ApiResponse({status: 404, description: 'Participant not found'})

Save (update) a participant PUT /api/client/participant/:id

Parameters :
Name Type Optional
id number No
data SaveParticipantDto No
auth CLAuthData No
import { CLAuthData, ClientAuth } from "@api/shared/decorators";
import { Public } from "@bish-nest/core/auth/decorator/public.decorator";
import {
  Body,
  Controller,
  Delete,
  Get,
  HttpCode,
  HttpStatus,
  NotFoundException,
  Param,
  ParseIntPipe,
  Post,
  Put,
  Query,
} from "@nestjs/common";
import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger";
import {
  AddParticipantDto,
  CLParticipantDto,
  CLParticipantListResponse,
  ParticipantActiveWorkDto,
  ParticipantQueryDto,
  SaveParticipantDto,
} from "./dto";
import { CLParticipantService } from "./participant.service";

@ApiTags("Client - Participants")
@Controller("api/client/participant")
export class CLParticipantController {
  constructor(private participantService: CLParticipantService) {}

  /**
   * Get all participants for client consumption with optional filtering and pagination
   * GET /api/client/participant?page=1&limit=20&sq=john&status=active&participantGroup=Sales
   */
  @HttpCode(HttpStatus.OK)
  @Public()
  @Get()
  @ApiOperation({
    summary: "Get all participants with pagination, search and filters",
    description:
      "Returns paginated participants filtered by search query, status, and participant group with metadata",
  })
  @ApiResponse({
    status: 200,
    description:
      "Returns paginated list of participants with metadata (page, limit, totalCount, totalPages, etc.)",
  })
  async getAllParticipants(
    @Query() query: ParticipantQueryDto,
    @ClientAuth() auth: CLAuthData,
  ): Promise<CLParticipantListResponse> {
    return this.participantService.getFilteredParticipants(
      auth.companyId,
      query.page || 1,
      query.limit || 20,
      query.sq,
      query.status,
      query.participantGroup,
      auth.participantId,
      auth.role,
    );
  }

  /**
   * Add a new participant
   * POST /api/client/participant
   */
  @HttpCode(HttpStatus.CREATED)
  @Public()
  @Post()
  @ApiOperation({ summary: "Add a new participant" })
  @ApiResponse({
    status: 201,
    description: "Participant added successfully",
    type: CLParticipantDto,
  })
  @ApiResponse({
    status: 409,
    description: "A contact with this email already exists",
  })
  async addParticipant(
    @Body() data: AddParticipantDto,
    @ClientAuth() auth: CLAuthData,
  ): Promise<CLParticipantDto> {
    return this.participantService.addParticipant(data, auth.companyId, auth.participantId);
  }

  /**
   * Get license availability for adding participants
   * GET /api/client/participant/license-availability
   */
  @HttpCode(HttpStatus.OK)
  @Public()
  @Get("license-availability")
  @ApiOperation({ summary: "Get license availability information" })
  @ApiResponse({
    status: 200,
    description: "Returns license availability information",
  })
  async getLicenseAvailability(@ClientAuth() auth: CLAuthData): Promise<{
    totalLicenses: number;
    currentActiveParticipants: number;
    availableSlots: number;
    canAddMore: boolean;
  }> {
    return this.participantService.getParticipantLicenseAvailability(auth.companyId);
  }

  /**
   * Check participant active work before deactivation
   * GET /api/client/participant/:id/active-work
   */
  @HttpCode(HttpStatus.OK)
  @Public()
  @Get(":id/active-work")
  @ApiOperation({
    summary: "Check if participant has active work",
    description: "Returns information about incomplete courses and pending assessments",
  })
  @ApiResponse({
    status: 200,
    description: "Returns active work information",
    type: ParticipantActiveWorkDto,
  })
  @ApiResponse({
    status: 400,
    description: "Participant not found",
  })
  async checkParticipantActiveWork(
    @Param("id", ParseIntPipe) id: number,
    @ClientAuth() auth: CLAuthData,
  ): Promise<ParticipantActiveWorkDto> {
    return this.participantService.checkParticipantActiveWork(id, auth.companyId);
  }

  /**
   * Get a single participant by ID
   * GET /api/client/participant/:id
   */
  @HttpCode(HttpStatus.OK)
  @Public()
  @Get(":id")
  @ApiOperation({ summary: "Get a participant by ID" })
  @ApiResponse({
    status: 200,
    description: "Returns a single participant with enriched data",
    type: CLParticipantDto,
  })
  @ApiResponse({
    status: 404,
    description: "Participant not found",
  })
  async getParticipantById(
    @Param("id", ParseIntPipe) id: number,
    @ClientAuth() auth: CLAuthData,
  ): Promise<CLParticipantDto> {
    const participant = await this.participantService.getParticipantById(id, auth.companyId);

    if (!participant) {
      throw new NotFoundException(`Participant with ID ${id} not found`);
    }

    return participant;
  }

  /**
   * Get the current participant's administrator
   * GET /api/client/participant/admin
   */
  @HttpCode(HttpStatus.OK)
  @Public()
  @Get("admin")
  @ApiOperation({
    summary: "Get the current participant's administrator",
    description: "Returns the Participant Administrator (User) who manages this participant for license allocation",
  })
  @ApiResponse({
    status: 200,
    description: "Returns the participant administrator's contact information",
  })
  @ApiResponse({
    status: 404,
    description: "Participant not found or no administrator assigned",
  })
  async getParticipantAdmin(@ClientAuth() auth: CLAuthData): Promise<{
    id: number;
    first_name: string;
    last_name: string;
    email: string;
    phone: string | null;
  } | null> {
    if (!auth.participantId) {
      throw new NotFoundException("Participant ID not found in authentication");
    }

    const admin = await this.participantService.getParticipantAdmin(
      auth.participantId,
      auth.companyId,
    );

    if (!admin) {
      throw new NotFoundException(
        "Participant administrator not found. Please contact your system administrator.",
      );
    }

    return admin;
  }

  /**
   * Save (update) a participant
   * PUT /api/client/participant/:id
   */
  @HttpCode(HttpStatus.OK)
  @Public()
  @Put(":id")
  @ApiOperation({ summary: "Save a participant" })
  @ApiResponse({
    status: 200,
    description: "Participant saved successfully",
    type: CLParticipantDto,
  })
  @ApiResponse({
    status: 404,
    description: "Participant not found",
  })
  async saveParticipant(
    @Param("id", ParseIntPipe) id: number,
    @Body() data: SaveParticipantDto,
    @ClientAuth() auth: CLAuthData,
  ): Promise<CLParticipantDto> {
    const participant = await this.participantService.saveParticipant(
      id,
      auth.companyId,
      data,
      auth.participantId,
    );

    if (!participant) {
      throw new NotFoundException(`Participant with ID ${id} not found`);
    }

    return participant;
  }

  /**
   * Delete a company contact. Participant administrator only; blocked when an active course allocation exists.
   * DELETE /api/client/participant/:id
   */
  @HttpCode(HttpStatus.NO_CONTENT)
  @Public()
  @Delete(":id")
  @ApiOperation({ summary: "Delete a participant contact" })
  @ApiResponse({ status: 204, description: "Participant deleted successfully" })
  @ApiResponse({ status: 403, description: "Forbidden — not a participant administrator" })
  @ApiResponse({
    status: 422,
    description: "Contact has an active course allocation and cannot be deleted",
  })
  async deleteParticipant(
    @Param("id", ParseIntPipe) id: number,
    @ClientAuth() auth: CLAuthData,
  ): Promise<void> {
    await this.participantService.deleteParticipantForParticipantAdmin(
      id,
      auth.companyId,
      auth.participantId,
      auth.role,
    );
  }
}

results matching ""

    No results matching ""