diff --git a/src/controllers/admin/mentee.controller.ts b/src/controllers/admin/mentee.controller.ts index d60498a6..d73df916 100644 --- a/src/controllers/admin/mentee.controller.ts +++ b/src/controllers/admin/mentee.controller.ts @@ -1,5 +1,5 @@ import type { Request, Response } from 'express' -import { ApplicationStatus, ProfileTypes } from '../../enums' +import { ApplicationStatus, ProfileTypes, StatusUpdatedBy } from '../../enums' import type Profile from '../../entities/profile.entity' import type Mentee from '../../entities/mentee.entity' import type { ApiResponse } from '../../types' @@ -54,7 +54,11 @@ export const updateMenteeStatus = async ( return res.status(403).json({ message: 'Only Admins are allowed' }) } - const { statusCode, message } = await updateStatus(menteeId, state) + const { statusCode, message } = await updateStatus( + menteeId, + state, + StatusUpdatedBy.ADMIN + ) return res.status(statusCode).json({ message }) } catch (err) { if (err instanceof Error) { diff --git a/src/controllers/mentee.controller.ts b/src/controllers/mentee.controller.ts index 945d2992..d6bd9d1a 100644 --- a/src/controllers/mentee.controller.ts +++ b/src/controllers/mentee.controller.ts @@ -3,7 +3,7 @@ import { type ApiResponse } from '../types' import type Mentee from '../entities/mentee.entity' import type Profile from '../entities/profile.entity' import { getMentee, updateStatus } from '../services/admin/mentee.service' -import { ApplicationStatus } from '../enums' +import { ApplicationStatus, StatusUpdatedBy } from '../enums' import { addMentee } from '../services/mentee.service' export const menteeApplicationHandler = async ( @@ -48,7 +48,11 @@ export const updateMenteeStatus = async ( return res.status(403).json({ message: 'Only mentors are allowed' }) } - const { statusCode, message } = await updateStatus(menteeId, state) + const { statusCode, message } = await updateStatus( + menteeId, + state, + StatusUpdatedBy.MENTOR + ) return res.status(statusCode).json({ message }) } catch (err) { if (err instanceof Error) { diff --git a/src/entities/mentee.entity.ts b/src/entities/mentee.entity.ts index e8cb7d44..9490c1c7 100644 --- a/src/entities/mentee.entity.ts +++ b/src/entities/mentee.entity.ts @@ -1,7 +1,7 @@ import { Column, Entity, JoinColumn, ManyToOne, OneToOne } from 'typeorm' import Mentor from './mentor.entity' import profileEntity from './profile.entity' -import { ApplicationStatus } from '../enums' +import { ApplicationStatus, StatusUpdatedBy } from '../enums' import BaseEntity from './baseEntity' @Entity('mentee') @@ -13,6 +13,12 @@ class Mentee extends BaseEntity { }) state: ApplicationStatus + @Column({ type: 'enum', enum: StatusUpdatedBy, nullable: true }) + status_updated_by!: StatusUpdatedBy + + @Column({ type: 'timestamp', nullable: true }) + status_updated_date!: Date + @Column({ type: 'json' }) application: Record diff --git a/src/enums/index.ts b/src/enums/index.ts index 2557093f..1760a198 100644 --- a/src/enums/index.ts +++ b/src/enums/index.ts @@ -14,3 +14,8 @@ export enum ApplicationStatus { REJECTED = 'rejected', APPROVED = 'approved' } + +export enum StatusUpdatedBy { + ADMIN = 'admin', + MENTOR = 'mentor' +} diff --git a/src/services/admin/mentee.service.ts b/src/services/admin/mentee.service.ts index 5613bdfe..264fe4dd 100644 --- a/src/services/admin/mentee.service.ts +++ b/src/services/admin/mentee.service.ts @@ -1,7 +1,7 @@ import { dataSource } from '../../configs/dbConfig' import Mentee from '../../entities/mentee.entity' import Mentor from '../../entities/mentor.entity' -import { ApplicationStatus } from '../../enums' +import { ApplicationStatus, type StatusUpdatedBy } from '../../enums' import { getEmailContent } from '../../utils' import { sendEmail } from './email.service' @@ -80,7 +80,8 @@ export const getAllMenteesByMentor = async ( export const updateStatus = async ( menteeId: string, - state: ApplicationStatus + state: ApplicationStatus, + statusUpdatedBy: StatusUpdatedBy ): Promise<{ statusCode: number updatedMenteeApplication?: Mentee @@ -120,7 +121,14 @@ export const updateStatus = async ( message: 'Mentee is already approved' } } else { - await menteeRepository.update({ uuid: menteeId }, { state }) + await menteeRepository.update( + { uuid: menteeId }, + { + state, + status_updated_by: statusUpdatedBy, + status_updated_date: new Date() + } + ) const content = getEmailContent( 'mentee', state, diff --git a/src/services/mentee.service.ts b/src/services/mentee.service.ts index 80bd8e68..d5869984 100644 --- a/src/services/mentee.service.ts +++ b/src/services/mentee.service.ts @@ -3,7 +3,7 @@ import Mentee from '../entities/mentee.entity' import Mentor from '../entities/mentor.entity' import type Profile from '../entities/profile.entity' import { ApplicationStatus } from '../enums' -import { getEmailContent } from '../utils' +import { getEmailContent, getMentorNotifyEmailContent } from '../utils' import { sendEmail } from './admin/email.service' export const addMentee = async ( @@ -82,12 +82,22 @@ export const addMentee = async ( application.firstName as string ) + const mentorContent = getMentorNotifyEmailContent( + mentor.application.firstName as string + ) + if (content) { await sendEmail( application.email as string, content.subject, content.message ) + + await sendEmail( + mentor.application.email as string, + mentorContent.subject, + mentorContent.message + ) } return { diff --git a/src/utils.ts b/src/utils.ts index 7e8d09ae..befdbf55 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -30,7 +30,7 @@ export const checkProfilePictureFileType = ( file: Express.Multer.File, cb: multer.FileFilterCallback ): void => { - const filetypes = /jpeg|jpg|png|gif/ + const filetypes = /jpeg|jpg|webp|png|gif/ const extname = filetypes.test(path.extname(file.originalname).toLowerCase()) const mimetype = filetypes.test(file.mimetype) @@ -88,7 +88,7 @@ export const getEmailContent = ( switch (status) { case ApplicationStatus.PENDING: return { - subject: 'Your ScholarX Mentor Application Status', + subject: 'Thank you very much for applying to ScholarX', message: `Dear ${name},

Thank you very much for applying to ScholarX. Your application has been received. Our team will soon review your application, and we will keep you posted on the progress via email. Please reach out to us via sustainableedufoundation@gmail.com for any clarifications.` @@ -106,7 +106,7 @@ export const getEmailContent = ( } case ApplicationStatus.REJECTED: return { - subject: 'ScholarX Mentor Application Status Update', + subject: 'Thank You for Your Interest in the ScholarX Program', message: `Dear ${name},

I hope this email finds you well. I wanted to take a moment to thank you for your interest in joining ScholarX as a mentor and for submitting your application. We appreciate the time and effort you put into it.

After careful review of your application and considering all of the candidates, we regret to inform you that we are unable to make you part of the mentor base at this time. We received a large number of qualified applicants, and unfortunately, we could only accept a limited number of mentors.

@@ -121,7 +121,7 @@ export const getEmailContent = ( switch (status) { case ApplicationStatus.PENDING: return { - subject: 'Your ScholarX Mentee Application Status', + subject: 'Thank you very much for applying to ScholarX', message: `Dear ${name},

Thank you very much for applying to ScholarX. Your application has been received. Mentor will soon review your application and we will keep you posted on the progress via email. Until then, read more about student experience here and reach out to us via sustainableedufoundation@gmail.com for any clarifications. ` } @@ -137,13 +137,13 @@ export const getEmailContent = ( } case ApplicationStatus.REJECTED: return { - subject: 'ScholarX Mentee Application Status Update', + subject: 'Thank You for Your Interest in the ScholarX Program', message: `Dear ${name},

We wanted to take a moment to thank you for your interest in the ScholarX program and for submitting your application. We appreciate the time and effort you put into it.

After a careful review of your application and considering all of the candidates, we regret to inform you that we are unable to offer you admission at this time. We received a large number of qualified applicants, and unfortunately, we could only accept a limited number of students.

However, we want to encourage you not to be discouraged by this decision. We recognize that the admissions process can be competitive, and we understand that this news may be disappointing. Please know that this does not reflect on your abilities, potential, or value as an individual.

We do offer the possibility for you to apply again next time if you meet the eligibility criteria. We invite you to stay engaged with us by attending our events, reaching out to our admissions team, and taking advantage of any opportunities to connect with our current students and alumni.

- Thank you again for considering our program and for the time you invested in your application. We wish you all the best in your future endeavours. ` + Thank you again for considering our program and for the time you invested in your application. We wish you all the best in your future endeavours.` } default: return undefined @@ -167,6 +167,20 @@ export const getPasswordResetEmailContent = ( } } +export const getMentorNotifyEmailContent = ( + name: string +): { subject: string; message: string } => { + return { + subject: 'New Mentee Application Received', + message: `Dear ${name},

+ We wanted to let you know that a new mentee has applied to be mentored by you through the ScholarX program. Please visit your dashboard to review their application at your earliest convenience.

+ If you have any questions or need assistance, feel free to reach out to us at sustainableedufoundation@gmail.com. +

+ Thank you for your continued support and commitment to the ScholarX program.

+ ` + } +} + export const getPasswordChangedEmailContent = ( name: string ): { subject: string; message: string } => {