diff --git a/backend/typescript/graphql/resolvers/reviewDashboardResolvers.ts b/backend/typescript/graphql/resolvers/reviewDashboardResolvers.ts index c1a41ec3..9b27c906 100644 --- a/backend/typescript/graphql/resolvers/reviewDashboardResolvers.ts +++ b/backend/typescript/graphql/resolvers/reviewDashboardResolvers.ts @@ -1,5 +1,8 @@ import ReviewDashboardService from "../../services/implementations/reviewDashboardService"; -import { ReviewDashboardRowDTO } from "../../types"; +import { + ReviewDashboardRowDTO, + ReviewDashboardSidePanelDTO, +} from "../../types"; import { getErrorMessage } from "../../utilities/errorUtils"; const reviewDashboardService = new ReviewDashboardService(); @@ -19,6 +22,18 @@ const reviewDashboardResolvers = { throw new Error(getErrorMessage(error)); } }, + reviewDashboardSidePanel: async ( + _parent: undefined, + args: { applicantId: string }, + ): Promise => { + try { + return await reviewDashboardService.getReviewDashboardSidePanel( + args.applicantId, + ); + } catch (error) { + throw new Error(getErrorMessage(error)); + } + }, }, }; diff --git a/backend/typescript/graphql/types/reviewDashboardType.ts b/backend/typescript/graphql/types/reviewDashboardType.ts index 0ef32093..c6b24643 100644 --- a/backend/typescript/graphql/types/reviewDashboardType.ts +++ b/backend/typescript/graphql/types/reviewDashboardType.ts @@ -17,11 +17,39 @@ const reviewDashboardType = gql` totalScore: Int } + type Review { + passionFSG: Int + teamPlayer: Int + desireToLearn: Int + skill: Int + skillCategory: String + comments: String + } + + type ReviewDetails { + reviewerFirstName: String! + reviewerLastName: String! + review: Review! + } + + type ReviewDashboardSidePanelDTO { + firstName: String! + lastName: String! + positionTitle: String! + program: String! + resumeUrl: String! + applicationStatus: String! + skillCategory: String + reviewDetails: [ReviewDetails!]! + } + extend type Query { reviewDashboard( pageNumber: Int! resultsPerPage: Int! ): [ReviewDashboardRowDTO!]! + + reviewDashboardSidePanel(applicantId: String!): ReviewDashboardSidePanelDTO! } `; diff --git a/backend/typescript/services/implementations/reviewDashboardService.ts b/backend/typescript/services/implementations/reviewDashboardService.ts index 8004c771..b094b680 100644 --- a/backend/typescript/services/implementations/reviewDashboardService.ts +++ b/backend/typescript/services/implementations/reviewDashboardService.ts @@ -1,4 +1,8 @@ -import { ReviewDashboardRowDTO } from "../../types"; +import { + PositionTitle, + ReviewDashboardRowDTO, + ReviewDashboardSidePanelDTO, +} from "../../types"; import IReviewDashboardService from "../interfaces/IReviewDashboardService"; import { getErrorMessage } from "../../utilities/errorUtils"; import logger from "../../utilities/logger"; @@ -22,6 +26,26 @@ function toDTO(model: ApplicantRecord): ReviewDashboardRowDTO { }; } +function toSidePanelDTO(model: ApplicantRecord): ReviewDashboardSidePanelDTO { + const reviewDetails = + model.reviewedApplicantRecords?.map((reviewRecord) => ({ + reviewerFirstName: reviewRecord.user?.first_name || "", + reviewerLastName: reviewRecord.user?.last_name || "", + review: reviewRecord.review, + })) || []; + + return { + firstName: model.applicant!.firstName, + lastName: model.applicant!.lastName, + positionTitle: model.position as PositionTitle, + program: model.applicant!.program, + resumeUrl: model.applicant!.resumeUrl, + applicationStatus: model.status, + skillCategory: model.skillCategory, + reviewDetails, + }; +} + class ReviewDashboardService implements IReviewDashboardService { /* eslint-disable class-methods-use-this */ async getReviewDashboard( @@ -72,6 +96,47 @@ class ReviewDashboardService implements IReviewDashboardService { throw error; } } + + async getReviewDashboardSidePanel( + applicantId: string, + ): Promise { + try { + const applicantRecord: ApplicantRecord | null = + await ApplicantRecord.findOne({ + where: { applicantId }, + attributes: { exclude: ["createdAt", "updatedAt"] }, + include: [ + { + attributes: { exclude: ["createdAt", "updatedAt"] }, + association: "reviewedApplicantRecords", + include: [ + { + attributes: { exclude: ["createdAt", "updatedAt"] }, + association: "user", + }, + ], + }, + { + attributes: { exclude: ["createdAt", "updatedAt"] }, + association: "applicant", + }, + ], + }); + + if (!applicantRecord || !applicantRecord.applicant) { + throw new Error(`Applicant with ID ${applicantId} not found`); + } + + return toSidePanelDTO(applicantRecord); + } catch (error: unknown) { + Logger.error( + `Failed to get review dashboard side panel for applicant ${applicantId}. Reason = ${getErrorMessage( + error, + )}`, + ); + throw error; + } + } } export default ReviewDashboardService; diff --git a/backend/typescript/services/interfaces/IReviewDashboardService.ts b/backend/typescript/services/interfaces/IReviewDashboardService.ts index 1c960b11..6090b23f 100644 --- a/backend/typescript/services/interfaces/IReviewDashboardService.ts +++ b/backend/typescript/services/interfaces/IReviewDashboardService.ts @@ -1,4 +1,7 @@ -import { ReviewDashboardRowDTO } from "../../types"; +import { + ReviewDashboardRowDTO, + ReviewDashboardSidePanelDTO, +} from "../../types"; interface IReviewDashboardService { /** @@ -10,6 +13,14 @@ interface IReviewDashboardService { page: number, resultsPerPage: number, ): Promise; + + /** + * Fetch data that can fill out the review dashboard side panel for an applicant + * @Param applicantId the ID of the applicant + */ + getReviewDashboardSidePanel( + applicantId: string, + ): Promise; } export default IReviewDashboardService; diff --git a/backend/typescript/types.ts b/backend/typescript/types.ts index 58254ab2..8a1b4de1 100644 --- a/backend/typescript/types.ts +++ b/backend/typescript/types.ts @@ -198,6 +198,7 @@ export type Review = { desireToLearn?: number; skill?: number; skillCategory?: SkillCategory; + comments?: string; }; export type ReviewedApplicantRecordDTO = { @@ -221,6 +222,23 @@ export type DeleteReviewedApplicantRecordDTO = { reviewerId: number; }; +export type ReviewDetails = { + reviewerFirstName: string; + reviewerLastName: string; + review: Review; +}; + +export type ReviewDashboardSidePanelDTO = { + firstName: string; + lastName: string; + positionTitle: PositionTitle; + program: string; + resumeUrl: string; + applicationStatus: ApplicationStatus; + skillCategory: SkillCategory | null; + reviewDetails: ReviewDetails[]; +}; + export type AdminCommentDTO = { id: string; userId: number;