Skip to content

Commit

Permalink
feat: add apply to a mentor reminder emails for con (#923)
Browse files Browse the repository at this point in the history
  • Loading branch information
helloanil authored Jun 26, 2024
1 parent 5bfcd3b commit fcc5955
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 146 deletions.
84 changes: 40 additions & 44 deletions apps/nestjs-api/src/reminder-emails/reminder-emails.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,53 +54,49 @@ export class ReminderEmailsController {
}
}

/**
* Following reminders are implemented but not working as expected.
* They will be tested and fixed in the next iterations.
*/

// @Get('/s3cr3t-3ndp01nt-t0-tr1gg3r-r3m1nd3r5/mentees-apply-to-mentor')
// async sendMenteeApplyToMentorReminders() {
// const firstReminderMentees =
// await this.reminderEmailsService.getApprovedMenteesWithNoMentorApplicationsByDays(
// {
// daysAgo: '7d',
// }
// )

// if (firstReminderMentees.length > 0) {
// // send reminder emails
// firstReminderMentees.forEach(async (mentee) => {
// await this.reminderEmailsService.sendApplyToMentorFirstReminder({
// email: mentee.props.email,
// firstName: mentee.props.firstName,
// location: mentee.props.rediLocation,
// })
// })
// }
@Get('/s3cr3t-3ndp01nt-t0-tr1gg3r-r3m1nd3r5/mentees-apply-to-mentor')
async sendMenteeApplyToMentorReminders() {
const firstReminderMentees =
await this.reminderEmailsService.getApprovedMenteesWithNoMentorApplicationsByDays(
{
daysAgo: '7d',
}
)

if (firstReminderMentees.length > 0) {
// send reminder emails
firstReminderMentees.forEach(async (mentee) => {
await this.reminderEmailsService.sendApplyToMentorReminder({
email: mentee.props.email,
firstName: mentee.props.firstName,
location: mentee.props.rediLocation,
})
})
}

// const secondReminderMentees =
// await this.reminderEmailsService.getApprovedMenteesWithNoMentorApplicationsByDays(
// {
// daysAgo: '14d',
// }
// )
const secondReminderMentees =
await this.reminderEmailsService.getApprovedMenteesWithNoMentorApplicationsByDays(
{
daysAgo: '14d',
}
)

// if (secondReminderMentees.length > 0) {
// // send reminder emails
// secondReminderMentees.forEach(async (mentee) => {
// await this.reminderEmailsService.sendApplyToMentorSecondReminder({
// email: mentee.props.email,
// firstName: mentee.props.firstName,
// location: mentee.props.rediLocation,
// })
// })
// }
if (secondReminderMentees.length > 0) {
// send reminder emails
secondReminderMentees.forEach(async (mentee) => {
await this.reminderEmailsService.sendApplyToMentorReminder({
email: mentee.props.email,
firstName: mentee.props.firstName,
location: mentee.props.rediLocation,
isSecondReminder: true,
})
})
}

// return {
// message: `First reminder emails to apply to a mentor sent to ${firstReminderMentees.length} mentees. Second reminder emails to apply to a mentor sent to ${secondReminderMentees.length} mentees`,
// }
// }
return {
message: `First reminder emails to apply to a mentor sent to ${firstReminderMentees.length} mentees. Second reminder emails to apply to a mentor sent to ${secondReminderMentees.length} mentees`,
}
}

@Get('/s3cr3t-3ndp01nt-t0-tr1gg3r-r3m1nd3r5/mentorship-follow-up')
async sendMentorshipFollowUpReminders() {
Expand Down
202 changes: 100 additions & 102 deletions apps/nestjs-api/src/reminder-emails/reminder-emails.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { ConfigService } from '@nestjs/config'
import {
ConnectProfileStatus,
MentorshipMatchStatus,
RediLocation,
UserType,
} from '@talent-connect/common-types'
import * as AWS from 'aws-sdk'
import * as jsforce from 'jsforce'
import difference from 'lodash/difference'
import transform from 'lodash/transform'
import { ConMentorshipMatchesService } from '../con-mentorship-matches/con-mentorship-matches.service'
import { ConProfilesService } from '../con-profiles/con-profiles.service'
Expand Down Expand Up @@ -45,24 +47,55 @@ export class ReminderEmailsService {
})
}

// async getApprovedMenteesWithNoMentorApplicationsByDays({
// daysAgo,
// }: {
// daysAgo: '7d' | '14d'
// }) {
// const approvedDate = new Date()
// approvedDate.setDate(approvedDate.getDate() - parseInt(daysAgo)) // Interestingly, parseInt is able to parse 7d and 14d to 7 and 14 respectively
async getApprovedMenteesWithNoMentorApplicationsByDays({
daysAgo,
}: {
daysAgo: '7d' | '14d'
}) {
const approvedDate = new Date()
approvedDate.setDate(approvedDate.getDate() - parseInt(daysAgo)) // Interestingly, parseInt is able to parse 7d and 14d to 7 and 14 respectively

// 1st Step: Get all approved mentees from the last 7 or 14 days
const approvedMentees = await this.conProfilesService.findAll({
'RecordType.DeveloperName': UserType.MENTEE,
Profile_Status__c: ConnectProfileStatus.APPROVED,
Profile_First_Approved_At__c: {
$eq: jsforce.SfDate.toDateLiteral(approvedDate),
},
})

// return this.conProfilesService.findAll({
// 'RecordType.DeveloperName': UserType.MENTEE,
// Profile_Status__c: ConnectProfileStatus.APPROVED,
// Profile_First_Approved_At__c: {
// $eq: jsforce.SfDate.toDateLiteral(approvedDate),
// },
// // When there are no applications, this field is not 0 but null/undefined
// 'Contact__r.ReDI_Active_Mentorship_Matches_Mentee__c': null,
// })
// }
const approvedMenteeIds = approvedMentees.map(
(mentee) => mentee.props.userId
)

if (approvedMenteeIds.length === 0) return []

// 2nd Step: Get all mentorship matches where the mentee is one of the approved mentees above
const mentorshipMatches = await this.conMentorshipMatchesService.findAll({
'Mentee__r.id': {
$in: approvedMenteeIds,
},
})

const mentorshipMatchMenteeIds = mentorshipMatches.map(
(match) => match.props.menteeId
)

// 3rd Step: Find approved mentees that do not have a mentorship match
const menteeIdsWithoutMentorshipMatch = difference(
approvedMenteeIds,
mentorshipMatchMenteeIds
)

// 4th Step: Return approved mentees that do not have a mentorship match
if (menteeIdsWithoutMentorshipMatch.length > 0) {
return approvedMentees.filter((mentee) =>
menteeIdsWithoutMentorshipMatch.includes(mentee.props.userId)
)
}

return []
}

async getThreeMonthsOldMentorshipMatches() {
const threeMonthsOldMentorshipMatches =
Expand Down Expand Up @@ -223,98 +256,63 @@ export class ReminderEmailsService {
return { message: 'Email sent' }
}

// async sendApplyToMentorFirstReminder({ email, firstName, location }) {
// const sfEmailTemplateDeveloperName =
// location === RediLocation.CYBERSPACE
// ? 'Cyberspace_Mentee_Apply_To_A_Mentor_Reminder_1_1711037205143'
// : 'Mentee_Apply_To_A_Mentor_Reminder_1_1695975263767'

// const template = await this.emailTemplatesService.getEmailTemplate(
// sfEmailTemplateDeveloperName
// )

// if (!template) {
// throw new Error(
// `Email template not found: ${sfEmailTemplateDeveloperName}`
// )
// }

// const sanitizedSubject = template.Subject.replace(
// /\${menteeFirstName}/g,
// `${firstName}`
// )

// const sanitizedHtml = template.HtmlValue.replace(
// /\${menteeFirstName}/g,
// `${firstName}`
// ).replace(/{{{Recipient\.FirstName}}}/g, `${firstName}`)

// const params = {
// Destination: {
// ToAddresses: isProductionOrDemonstration()
// ? [email]
// : [this.config.get('NX_DEV_MODE_EMAIL_RECIPIENT')],
// },
// Message: {
// Body: {
// Html: { Data: sanitizedHtml },
// },
// Subject: { Data: sanitizedSubject },
// },
// Source: 'career@redi-school.org',
// }

// this.ses.sendEmail(params, (err, data) => {
// if (err) console.log(err, err.stack)
// else console.log(data)
// })

// return { message: 'Email sent' }
// }
async sendApplyToMentorReminder({
email,
firstName,
location,
isSecondReminder = false,
}) {
const sfEmailTemplateDeveloperName = !isSecondReminder
? location === RediLocation.CYBERSPACE
? 'Cyberspace_Mentee_Apply_To_A_Mentor_Reminder_1_1711037205143'
: 'Mentee_Apply_To_A_Mentor_Reminder_1_1695975263767'
: location === RediLocation.CYBERSPACE
? 'Cyberspace_Mentee_Apply_To_A_Mentor_Reminder_2_1711109460383'
: 'Mentee_Apply_To_A_Mentor_Reminder_2_1695975868066'

// async sendApplyToMentorSecondReminder({ email, firstName, location }) {
// const sfEmailTemplateDeveloperName =
// location === RediLocation.CYBERSPACE
// ? 'Cyberspace_Mentee_Apply_To_A_Mentor_Reminder_2_1711109460383'
// : 'Mentee_Apply_To_A_Mentor_Reminder_2_1695975868066'
const template = await this.emailTemplatesService.getEmailTemplate(
sfEmailTemplateDeveloperName
)

// const template = await this.emailTemplatesService.getEmailTemplate(
// sfEmailTemplateDeveloperName
// )
if (!template) {
throw new Error(
`Email template not found: ${sfEmailTemplateDeveloperName}`
)
}

// if (!template) {
// throw new Error(
// `Email template not found: ${sfEmailTemplateDeveloperName}`
// )
// }
const sanitizedSubject = template.Subject.replace(
/\${menteeFirstName}/g,
`${firstName}`
)

// const sanitizedHtml = template.HtmlValue.replace(
// /{{{Recipient\.FirstName}}}/g,
// `${firstName}`
// )
const sanitizedHtml = template.HtmlValue.replace(
/\${menteeFirstName}/g,
`${firstName}`
).replace(/{{{Recipient\.FirstName}}}/g, `${firstName}`)

// const params = {
// Destination: {
// ToAddresses: isProductionOrDemonstration()
// ? [email]
// : [this.config.get('NX_DEV_MODE_EMAIL_RECIPIENT')],
// },
// Message: {
// Body: {
// Html: { Data: sanitizedHtml },
// },
// Subject: { Data: template.Subject },
// },
// Source: 'career@redi-school.org',
// }
const params = {
Destination: {
ToAddresses: isProductionOrDemonstration()
? [email]
: [this.config.get('NX_DEV_MODE_EMAIL_RECIPIENT')],
BccAddresses: ['career@redi-school.org'],
},
Message: {
Body: {
Html: { Data: sanitizedHtml },
},
Subject: { Data: sanitizedSubject },
},
Source: 'career@redi-school.org',
}

// this.ses.sendEmail(params, (err, data) => {
// if (err) console.log(err, err.stack)
// else console.log(data)
// })
this.ses.sendEmail(params, (err, data) => {
if (err) console.log(err, err.stack)
else console.log(data)
})

// return { message: 'Email sent' }
// }
return { message: 'Email sent' }
}

async sendMentorshipFollowUpReminder({
email,
Expand Down

0 comments on commit fcc5955

Please sign in to comment.