Skip to content

Commit

Permalink
#1954 - Request an Offering Change - Submit/View UI (Part 1) (#2105)
Browse files Browse the repository at this point in the history
- Added a new endpoint to submit the request.
- Added new endpoint to get the request details submitted:
`@Get(":applicationOfferingChangeRequestId")`
- Reused methods to load programs and offerings from PIR.
- Created a component to display an offering summary to be used for the
student offering change and with the potential to be used for scholastic
standings and COE approvals.
- Created a component to submit the requested change and visualize it.
- Method `getEligibleApplications` was reused to also retrieve the
"change request"/"application details" to allow the submission. In this
way, the same query constraints are used to load the summary list and
also to get more details for the same item that will be submitted. New
endpoint added as `@Get("available/application/:applicationId")`.

### Fixes and UI refactors
- Fixed query for available applications that was showing the
application available to report a change when there was one already in
progress and also completed.
- Removed extra space from `detail-header` after the label. Instead of
showing `label : value` it will now show `label: value`.
- Replace the "vertical divider" in `detail-header` with a pipe ("|") as
per Figma.
- Fixed the `body-header` `#status-chip` that was being displayed in the
second line.
  • Loading branch information
andrewsignori-aot authored Jul 13, 2023
1 parent cdfd62a commit 8192320
Show file tree
Hide file tree
Showing 36 changed files with 1,504 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getComplet
.expect({
results: [
{
id: declinedBySABCApplicationOfferingChange.id,
applicationNumber:
applicationWithDeclinedBySABCApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand All @@ -168,6 +169,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getComplet
declinedBySABCApplicationOfferingChange.assessedDate.toISOString(),
},
{
id: declinedByStudentApplicationOfferingChange.id,
applicationNumber:
applicationWithDeclinedByStudentApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand All @@ -186,6 +188,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getComplet
declinedByStudentApplicationOfferingChange.studentActionDate.toISOString(),
},
{
id: approvedApplicationOfferingChange.id,
applicationNumber:
applicationWithApprovedApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand Down Expand Up @@ -312,6 +315,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getComplet
.expect({
results: [
{
id: approvedApplicationOfferingChange.id,
applicationNumber:
applicationWithApprovedApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand All @@ -329,6 +333,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getComplet
approvedApplicationOfferingChange.assessedDate.toISOString(),
},
{
id: declinedBySABCApplicationOfferingChange.id,
applicationNumber:
applicationWithDeclinedBySABCApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getInProgr
.expect({
results: [
{
id: inProgressWithSABCApplicationOfferingChange.id,
applicationNumber:
applicationWithInProgressWithSABCApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand All @@ -137,6 +138,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getInProgr
inProgressWithSABCApplicationOfferingChange.applicationOfferingChangeRequestStatus,
},
{
id: inProgressWithStudentApplicationOfferingChange.id,
applicationNumber:
applicationWithInProgressWithStudentApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand Down Expand Up @@ -203,6 +205,7 @@ describe("ApplicationOfferingChangeRequestInstitutionsController(e2e)-getInProgr
.expect({
results: [
{
id: inProgressWithSABCApplicationOfferingChange.id,
applicationNumber:
applicationWithInProgressWithSABCApplicationOfferingChange.applicationNumber,
studyStartDate:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { Controller, Get, Param, ParseIntPipe, Query } from "@nestjs/common";
import { ApiTags } from "@nestjs/swagger";
import {
Body,
Controller,
Get,
NotFoundException,
Param,
ParseIntPipe,
Post,
Query,
} from "@nestjs/common";
import { ApiNotFoundResponse, ApiTags } from "@nestjs/swagger";
import { AuthorizedParties } from "../../auth/authorized-parties.enum";
import { AllowAuthorizedParty, HasLocationAccess } from "../../auth/decorators";
import {
AllowAuthorizedParty,
HasLocationAccess,
UserToken,
} from "../../auth/decorators";
import { ClientTypeBaseRoute } from "../../types";
import { getUserFullName } from "../../utilities";
import { PaginatedResultsAPIOutDTO } from "../models/pagination.dto";
Expand All @@ -13,9 +26,14 @@ import {
OfferingChangePaginationOptionsAPIInDTO,
InProgressOfferingChangePaginationOptionsAPIInDTO,
CompletedOfferingChangePaginationOptionsAPIInDTO,
ApplicationOfferingChangesAPIOutDTO,
ApplicationOfferingChangeSummaryDetailAPIOutDTO,
CreateApplicationOfferingChangeRequestAPIInDTO,
} from "./models/application-offering-change-request.institutions.dto";
import { ApplicationOfferingChangeRequestService } from "../../services";
import { ApplicationOfferingChangeRequestStatus } from "@sims/sims-db";
import { PrimaryIdentifierAPIOutDTO } from "../models/primary.identifier.dto";
import { IInstitutionUserToken } from "../../auth";

/**
* Application offering change request controller for institutions client.
Expand Down Expand Up @@ -51,7 +69,7 @@ export class ApplicationOfferingChangeRequestInstitutionsController extends Base
const applications =
await this.applicationOfferingChangeRequestService.getEligibleApplications(
locationId,
pagination,
{ pagination },
);
return {
results: applications.results.map((eachApplication) => {
Expand All @@ -68,6 +86,42 @@ export class ApplicationOfferingChangeRequestInstitutionsController extends Base
};
}

/**
* Gets an eligible application that can be requested for application
* offering change.
* @param locationId location id.
* @param applicationId application id.
* @returns eligible application.
*/
@ApiNotFoundResponse({
description: "Application not found or it is not eligible.",
})
@Get("available/application/:applicationId")
async getEligibleApplication(
@Param("locationId", ParseIntPipe) locationId: number,
@Param("applicationId", ParseIntPipe) applicationId: number,
): Promise<ApplicationOfferingChangeSummaryDetailAPIOutDTO> {
const application =
await this.applicationOfferingChangeRequestService.getEligibleApplications(
locationId,
{ applicationId },
);
if (!application) {
throw new NotFoundException(
"Application not found or it is not eligible.",
);
}
return {
applicationNumber: application.applicationNumber,
programId: application.currentAssessment.offering.educationProgram.id,
offeringId: application.currentAssessment.offering.id,
offeringIntensity:
application.currentAssessment.offering.offeringIntensity,
programYearId: application.programYear.id,
fullName: getUserFullName(application.student.user),
};
}

/**
* Get all in progress application offering change requests.
* @param locationId location id.
Expand Down Expand Up @@ -95,6 +149,7 @@ export class ApplicationOfferingChangeRequestInstitutionsController extends Base
const offering =
eachOfferingChange.application.currentAssessment.offering;
return {
id: eachOfferingChange.id,
applicationNumber: eachOfferingChange.application.applicationNumber,
applicationId: eachOfferingChange.application.id,
studyStartDate: offering.studyStartDate,
Expand Down Expand Up @@ -137,6 +192,7 @@ export class ApplicationOfferingChangeRequestInstitutionsController extends Base
const offering =
eachOfferingChange.application.currentAssessment.offering;
return {
id: eachOfferingChange.id,
applicationNumber: eachOfferingChange.application.applicationNumber,
applicationId: eachOfferingChange.application.id,
studyStartDate: offering.studyStartDate,
Expand All @@ -153,4 +209,70 @@ export class ApplicationOfferingChangeRequestInstitutionsController extends Base
count: offeringChange.count,
};
}

/**
* Gets the Application Offering Change Request details.
* @param applicationOfferingChangeRequestId the Application Offering Change Request id.
* @param locationId location id.
* @returns Application Offering Change Request details.
*/
@Get(":applicationOfferingChangeRequestId")
@ApiNotFoundResponse({
description: "Not able to find an Application Offering Change Request.",
})
async getById(
@Param("applicationOfferingChangeRequestId", ParseIntPipe)
applicationOfferingChangeRequestId: number,
@Param("locationId", ParseIntPipe) locationId: number,
): Promise<ApplicationOfferingChangesAPIOutDTO> {
const request = await this.applicationOfferingChangeRequestService.getById(
applicationOfferingChangeRequestId,
{ locationId },
);
if (!request) {
throw new NotFoundException(
"Not able to find an Application Offering Change Request.",
);
}
return {
id: request.id,
status: request.applicationOfferingChangeRequestStatus,
applicationId: request.application.id,
applicationNumber: request.application.applicationNumber,
locationName: request.application.location.name,
activeOfferingId: request.activeOffering.id,
requestedOfferingId: request.requestedOffering.id,
requestedOfferingDescription: request.requestedOffering.name,
requestedOfferingProgramId: request.requestedOffering.educationProgram.id,
requestedOfferingProgramName:
request.requestedOffering.educationProgram.name,
reason: request.reason,
assessedNoteDescription: request.assessedNote?.description,
studentFullName: getUserFullName(request.application.student.user),
};
}

/**
* Creates a new application offering change request.
* @param locationId location id.
* @param payload information to create the new request.
* @returns newly change request id created.
*/
@Post()
async createApplicationOfferingChangeRequest(
@UserToken() userToken: IInstitutionUserToken,
@Param("locationId", ParseIntPipe) locationId: number,
@Body() payload: CreateApplicationOfferingChangeRequestAPIInDTO,
): Promise<PrimaryIdentifierAPIOutDTO> {
// TODO: Apply the same validations from PIR.
const applicationOfferingChangeRequest =
await this.applicationOfferingChangeRequestService.createRequest(
locationId,
payload.applicationId,
payload.offeringId,
payload.reason,
userToken.userId,
);
return { id: applicationOfferingChangeRequest.id };
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { ApplicationOfferingChangeRequestStatus } from "@sims/sims-db";
import { IsIn, IsOptional } from "class-validator";
import {
ApplicationOfferingChangeRequestStatus,
OfferingIntensity,
REASON_MAX_LENGTH,
} from "@sims/sims-db";
import {
IsIn,
IsNotEmpty,
IsOptional,
IsPositive,
MaxLength,
} from "class-validator";
import { PaginationOptionsAPIInDTO } from "../../models/pagination.dto";

/**
Expand All @@ -13,10 +23,23 @@ export class ApplicationOfferingChangeSummaryAPIOutDTO {
fullName: string;
}

/**
* Applications details for an eligible application to request an offering change.
*/
export class ApplicationOfferingChangeSummaryDetailAPIOutDTO {
applicationNumber: string;
programId: number;
offeringId: number;
offeringIntensity: OfferingIntensity;
programYearId: number;
fullName: string;
}

/**
* In progress application offering change details.
*/
export class InProgressApplicationOfferingChangesAPIOutDTO {
id: number;
applicationNumber: string;
applicationId: number;
studyStartDate: string;
Expand All @@ -29,6 +52,7 @@ export class InProgressApplicationOfferingChangesAPIOutDTO {
* Completed application offering change details.
*/
export class CompletedApplicationOfferingChangesAPIOutDTO {
id: number;
applicationNumber: string;
applicationId: number;
studyStartDate: string;
Expand Down Expand Up @@ -64,3 +88,35 @@ export class InProgressOfferingChangePaginationOptionsAPIInDTO extends Paginatio
@IsIn(["applicationNumber", "fullName"])
sortField?: string;
}

/**
* Application Offering Change Request details.
*/
export class ApplicationOfferingChangesAPIOutDTO {
id: number;
status: ApplicationOfferingChangeRequestStatus;
applicationId: number;
applicationNumber: string;
locationName: string;
activeOfferingId: number;
requestedOfferingId: number;
requestedOfferingDescription: string;
requestedOfferingProgramId: number;
requestedOfferingProgramName: string;
reason?: string;
assessedNoteDescription?: string;
studentFullName: string;
}

/**
* Information provided by the institution to create a new Application Offering Change Request.
*/
export class CreateApplicationOfferingChangeRequestAPIInDTO {
@IsPositive()
applicationId: number;
@IsPositive()
offeringId: number;
@IsNotEmpty()
@MaxLength(REASON_MAX_LENGTH)
reason: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ export class EducationProgramOfferingAESTController extends BaseController {
): Promise<EducationProgramOfferingAPIOutDTO> {
const offering = await this.programOfferingService.getOfferingById(
offeringId,
true,
{ isPrecedingOffering: true },
);
if (!offering) {
throw new NotFoundException("Offering not found.");
Expand Down
Loading

0 comments on commit 8192320

Please sign in to comment.