-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TEC email reminders feature #536
Conversation
[diff-counting] Significant lines: 232. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also list out the available upcoming TEC events in bulleted form in the email?
backend/src/API/memberAPI.ts
Outdated
@@ -74,6 +75,25 @@ export const deleteMember = async (email: string, user: IdolMember): Promise<voi | |||
); | |||
}; | |||
|
|||
export const notifyMember = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be TeamEvent specific. Consider putting this in teamEventAPI
instead?
@@ -5,6 +5,10 @@ export default class PermissionsManager { | |||
return this.isLeadOrAdmin(mem); | |||
} | |||
|
|||
static async canNotifyMembers(mem: IdolMember): Promise<boolean> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
backend/src/api.ts
Outdated
@@ -219,6 +220,9 @@ loginCheckedDelete('/member/:email', async (req, user) => { | |||
loginCheckedPut('/member', async (req, user) => ({ | |||
member: await updateMember(req, req.body, user) | |||
})); | |||
loginCheckedPost('/notifyMember', async (req, user) => ({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/team-event-reminder
?
Let's also specify the requirement along with how many they have already accumulated. That will give some of them a sense of urgency if it's low. |
backend/src/API/mailAPI.ts
Outdated
export const sendTECReminder = async (req: Request, member: IdolMember): Promise<AxiosResponse> => { | ||
const subject = 'TEC Reminder'; | ||
const text = | ||
'Hey! You currently do not have enough team events credits this semester. This is a reminder to get at least 3 team events credits by the end of the semester.'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make the credit amount custom based on the role type? Leads need 6 credits, all other members need only 3.
Don't send emails for non-prod environments :) (e.g. dev and staging) Don't wanna alarm and upset anyone xD |
} | ||
|
||
if (all && members) { | ||
members.map((member) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could just do a forEach
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make sure to also await the MembersAPI.notifyMember(member);
backend/src/API/mailAPI.ts
Outdated
const memberEvents = getTeamEventAttendanceByUser(member); | ||
let approvedCount = 0; | ||
let pendingCount = 0; | ||
(await memberEvents).map((event) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could do a forEach
here, or use a reduce
to be a bit more idiomatic (but for the reduce
you will have to traverse the list twice, but that is ok)
backend/src/API/mailAPI.ts
Outdated
if (event.status === 'approved') { | ||
approvedCount += 1; | ||
} | ||
if (event.pending) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
event.status === 'pending'
, we're in the process of a DB schema change driven by this: #521
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the last nitpicks! We should be good after this.
backend/src/API/teamEventsAPI.ts
Outdated
*/ | ||
export const notifyMember = async ( | ||
req: Request, | ||
body: IdolMember, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: How about we change body
to member
?
backend/src/API/teamEventsAPI.ts
Outdated
/** | ||
* Reminds a member about completing enough TECs this semester. | ||
* @param req - the post request being made by the user | ||
* @param user - the user trying to notify member(s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Add member
to the docstring
backend/src/API/mailAPI.ts
Outdated
`Hey! You currently have ${approvedCount} team event credits approved and ${pendingCount} team event credits pending this semester. ` + | ||
`This is a reminder to get at least ${ | ||
member.role === 'lead' ? '6' : '3' | ||
} team events credits by the end of the semester.\n` + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: *team event
export const sendMemberUpdateNotifications = async (req: Request): Promise<Promise<void>[]> => { | ||
const subject = 'IDOL Member Profile Change'; | ||
const text = | ||
'Hey! A DTI member has updated their profile on IDOL. Please visit https://idol.cornelldti.org/admin/member-review to review the changes.'; | ||
return emailAdmins(req, subject, text); | ||
}; | ||
|
||
export const sendTECReminder = async (req: Request, member: IdolMember): Promise<AxiosResponse> => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are creating variables with promises, I'd await them first instead of inlining the await
, otherwise you might as well just inline the value and delete the variable entirely.
So instead of
const allEvents = getAllTeamEvents(req.body);
const futureEvents = (await allEvents).filter((event) => {
try
const allEvents = await getAllTeamEvents(req.body);
const futureEvents = allEvents.filter((event) => {
Same with memberEvents
, although I'd personally rename this to memberEventAttendance
backend/src/API/mailAPI.ts
Outdated
const memberEvents = getTeamEventAttendanceByUser(member); | ||
let approvedCount = 0; | ||
let pendingCount = 0; | ||
(await memberEvents).forEach((event) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's probably more clear to tell a user how many credits they have pending than the number of requests they still have pending.
How about something like this?
memberEvents.forEach((eventAttendance) => {
const eventCredit = Number(allEvents.find((event) => event.uuid === eventAttendance.eventUuid)?.numCredits ?? 0);
if (eventAttendance.status === 'approved') {
approvedCount += eventCredit;
}
if (eventAttendance.status === 'pending') {
pendingCount += eventCredit;
}
});
backend/src/API/mailAPI.ts
Outdated
} team events credits by the end of the semester.\n` + | ||
`\n${ | ||
futureEvents.length === 0 | ||
? 'There are currently no upcoming team events, but check IDOL soon for updates.' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check IDOL soon for updates
Thoughts on changing this to There are currently no upcoming team events listed on IDOL, but check the #team-events channel for upcoming team events
.
backend/src/API/mailAPI.ts
Outdated
Number(event.numCredits) !== 1 ? 'credits' : 'credit' | ||
})\n` | ||
) | ||
.join('')}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about at the end of the message we add:
"To submit your TEC, please visit https://idol.cornelldti.org/forms/teamEventCredits."
@patriciaahuang I'll add this change in another PR: #541. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent!! Justin's going to love this.
Summary
Implemented a new feature on the TEC dashboard that can either remind individual people or everyone who doesn't have enough TECs that they do not have enough TECs completed yet this semester.
Notion Link
https://www.notion.so/TEC-Add-Support-for-Email-Reminders-07b6c3d821af4eff8cde00d3c9048f37?pvs=4
Test Plan
I checked that the POST requests to /sendMail were successful for both individual reminders and the remind all feature.
To ensure an email actually sends to the members, I tested sending a reminder email to myself, which worked.