Skip to content

Commit

Permalink
Implemented invitation functionality (#149)
Browse files Browse the repository at this point in the history
  • Loading branch information
Aime-Patrick authored Nov 28, 2024
1 parent 6e45d84 commit 328dfce
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 77 deletions.
2 changes: 1 addition & 1 deletion src/models/AuthUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const userSchema = new Schema(
},
applicationPhase: {
type: String,
enum: ["Applied", "Interviewed", "Accepted", "Enrolled"],
enum: ["Applied", 'Shortlisted', 'Technical Assessment', 'Interview Assessment', 'Admitted', 'Rejected', "Enrolled"],
default: "Applied",
},
isActive: {
Expand Down
4 changes: 2 additions & 2 deletions src/models/ShortlistedSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import mongoose, { Schema, Document } from "mongoose";

interface IShortlisted extends Document {
applicantId: mongoose.Schema.Types.ObjectId;
status: "No action" | "Moved" | "Rejected" | "Admitted";
status: "No action" | "Invited" | "Moved" | "Rejected" | "Admitted";
comments?: string;
}

Expand All @@ -15,7 +15,7 @@ const shortlistedSchema = new Schema<IShortlisted>({
},
status: {
type: String,
enum: ["No action", "Moved", "Rejected", "Admitted"],
enum: ["No action", "Invited", "Moved", "Rejected", "Admitted"],
default: "No action",
},
comments: {
Expand Down
12 changes: 10 additions & 2 deletions src/models/technicalAssessmentStage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import mongoose, { Schema, Document } from "mongoose";

interface ITechnicalAssessment extends Document {
applicantId: mongoose.Schema.Types.ObjectId;
status: "No action" | "Moved" | "Rejected" | "Admitted";
status: "No action" | "Invited"| "Moved" | "Rejected" | "Admitted";
score: number;
invitationLink: string;
platform:string;
comments?: string;
}

Expand All @@ -15,7 +17,7 @@ const technicalAssessmentSchema = new Schema<ITechnicalAssessment>({
},
status: {
type: String,
enum: ["No action", "Moved", "Rejected", "Admitted"],
enum: ["No action", "Invited", "Moved", "Rejected", "Admitted"],
default: "No action",
},
score: {
Expand All @@ -24,6 +26,12 @@ const technicalAssessmentSchema = new Schema<ITechnicalAssessment>({
max: 100,
default:null
},
platform:{
type:String,
},
invitationLink:{
type:String,
},
comments: {
type: String,
},
Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/Doc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const docResolver:any={
return doc;
},
async deleteDoc(_:any,args:any){
const doc= await docModels.findOneAndDelete({id:args.id})
const doc= await docModels.findOneAndDelete({_id:args.id})
return doc;
},
async updateDoc(_:any,args:any){
Expand Down
108 changes: 97 additions & 11 deletions src/resolvers/applicationStageResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ const models = [
async function getApplicantsByModel(model: any) {
return await model.find().populate("applicantId").exec();
}
async function updateApplicantAfterDismissed(model: any, applicantId: string) {
async function updateApplicantAfterRejected(model: any, applicantId: string) {
await model.updateOne({ applicantId }, { $set: { status: "Rejected" } });
}
async function updateApplicantAfterAdmitted(model: any,applicantId:string) {
async function updateApplicantAfterAdmitted(model: any, applicantId: string) {
await model.updateOne({ applicantId }, { $set: { status: "Admitted" } });
}
export const applicationStageResolvers: any = {
Expand Down Expand Up @@ -85,6 +85,8 @@ export const applicationStageResolvers: any = {
status: tracking.status,
score: tracking.score || tracking.interviewScore,
comments: tracking.comments,
platform: tracking.platform,
invitationLink: tracking.invitationLink,
createdAt: tracking.createdAt.toLocaleString(),
updatedAt: tracking.updatedAt.toLocaleString(),
}));
Expand Down Expand Up @@ -148,7 +150,7 @@ export const applicationStageResolvers: any = {
technicalStage,
interviewStage,
admittedStage,
dismissedStage,
rejectedStage,
AllStages,
] = await Promise.all([
Shortlisted.findOne({ applicantId: trainee }),
Expand All @@ -164,7 +166,7 @@ export const applicationStageResolvers: any = {
technical: technicalStage,
interview: interviewStage,
admitted: admittedStage,
dismissed: dismissedStage,
rejected: rejectedStage,
allStages: AllStages,
};
} catch (error) {
Expand Down Expand Up @@ -301,7 +303,7 @@ export const applicationStageResolvers: any = {
await TraineeApplicant.updateOne(
{ _id: applicantId },
{ $set: { applicationPhase: nextStage, status: "No action" } }
);
);
message = `You have advanced to the ${nextStage} stage.`;
const notification = await ApplicantNotificationsModel.create({
userId: user!._id,
Expand Down Expand Up @@ -477,23 +479,23 @@ export const applicationStageResolvers: any = {
}
await Promise.all(
models.map((model) =>
updateApplicantAfterDismissed(model, applicantId)
updateApplicantAfterRejected(model, applicantId)
)
);
const stageDismissedFrom = await TraineeApplicant.findOne({
const stageRejectedFrom = await TraineeApplicant.findOne({
_id: applicantId,
});
await Rejected.create({
applicantId,
stageDismissedFrom: stageDismissedFrom?.applicationPhase,
stageRejectedFrom: stageRejectedFrom?.applicationPhase,
comments,
});
await TraineeApplicant.updateOne(
{ _id: applicantId },
{ $set: { applicationPhase: "Rejected", status: "Rejected" } }
);
message = `You have been rejected from the ${stageDismissedFrom?.applicationPhase} stage.`;
message = `You have been rejected from the ${stageRejectedFrom?.applicationPhase} stage.`;

const notification3 = await ApplicantNotificationsModel.create({
userId: user!._id,
message,
Expand All @@ -505,7 +507,7 @@ export const applicationStageResolvers: any = {
"Application Update",
`Hello ${user!.email.split("@")[0]}, `,
`We are sorry to inform you that
your application has been rejected from the ${stageDismissedFrom?.applicationPhase} stage.
your application has been rejected from the ${stageRejectedFrom?.applicationPhase} stage.
<br />
<br />
You can always apply again.
Expand Down Expand Up @@ -639,5 +641,89 @@ export const applicationStageResolvers: any = {
return new Error(error.message);
}
},
sendInvitation: async ( _: any, { applicantId, email, platform,invitationLink,}: { applicantId: string; email: string; platform: string; invitationLink: string;}, context: any) => {
try {
if (!context.currentUser) {
throw new CustomGraphQLError(
"You must be logged in to perform this action."
);
}

if (!email || !invitationLink) {
throw new CustomGraphQLError(
"Email and invitation link are required."
);
}

// Find the applicant
const isApplicantExist = await TechnicalAssessment.findOne({
applicantId,
})
.populate("applicantId")
.exec();

if (!isApplicantExist || !isApplicantExist.applicantId) {
throw new Error("Applicant not found or applicantId is missing.");
}

const user = await LoggedUserModel.findOne({ email });
const applicant = isApplicantExist.applicantId as any;
const firstName = applicant.firstName;
const lastName = applicant.lastName;
const notification = await ApplicantNotificationsModel.create({
userId: user!._id,
message:"Invitation link has sent to your email address. Please check your email address",
eventType: "general",
});
await pusher
.trigger(`notifications-${user!._id}`, "new-notification", {
message: notification.message,
id: notification._id,
createdAt: notification.createdAt,
read: notification.read,
})
.catch((error) => {
console.error("Error with Pusher trigger:", error);
});
await sendEmailTemplate(
email,
"Invitation to Complete Technical Assessment",
`Dear ${firstName} ${lastName},`,
` <p>
We are excited to invite you to take the next step in your application process! <br>
Please complete the following technical assessment to continue:<br>
<a href="${invitationLink}" target="_blank">${invitationLink}</a><br>
The assessment will be hosted on the <strong>${platform}</strong> platform. Please ensure that you have the necessary access and requirements ready.
</p>
<p>
Once you've finished the assessment, we'll review your results and follow up with the next steps.
</p>
`,
{
text: "Invitation link",
url: invitationLink,
}
);

await TraineeApplicant.updateOne(
{ _id: applicantId },
{ $set: { status: "Invited" } }
);
await TechnicalAssessment.updateOne(
{ applicantId },
{ $set: { status: "Invited" ,invitationLink, platform} }
);

return {
success: true,
message: "Invitation sent successfully",
};
} catch (error: any) {
return {
success: false,
message: error.message,
};
}
},
},
};
Loading

0 comments on commit 328dfce

Please sign in to comment.