Skip to content
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

Merged
merged 6 commits into from
Nov 12, 2023
Merged

TEC email reminders feature #536

merged 6 commits into from
Nov 12, 2023

Conversation

patriciaahuang
Copy link
Contributor

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.

Screen Shot 2023-11-04 at 3 55 06 PM

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.
Screen Shot 2023-10-31 at 12 07 34 PM

To ensure an email actually sends to the members, I tested sending a reminder email to myself, which worked.
Screen Shot 2023-11-04 at 4 03 26 PM

@patriciaahuang patriciaahuang requested a review from a team as a code owner November 4, 2023 20:04
@dti-github-bot
Copy link
Member

dti-github-bot commented Nov 4, 2023

[diff-counting] Significant lines: 232.

Copy link
Collaborator

@andrew032011 andrew032011 left a 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?

@@ -74,6 +75,25 @@ export const deleteMember = async (email: string, user: IdolMember): Promise<voi
);
};

export const notifyMember = async (
Copy link
Collaborator

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> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -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) => ({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/team-event-reminder?

@andrew032011
Copy link
Collaborator

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.

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.';
Copy link
Collaborator

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.

@henry-li-06
Copy link
Collaborator

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) => {
Copy link
Collaborator

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.

Copy link
Collaborator

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);

const memberEvents = getTeamEventAttendanceByUser(member);
let approvedCount = 0;
let pendingCount = 0;
(await memberEvents).map((event) => {
Copy link
Collaborator

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)

if (event.status === 'approved') {
approvedCount += 1;
}
if (event.pending) {
Copy link
Collaborator

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

Copy link
Collaborator

@andrew032011 andrew032011 left a 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.

*/
export const notifyMember = async (
req: Request,
body: IdolMember,
Copy link
Collaborator

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?

/**
* 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)
Copy link
Collaborator

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

`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` +
Copy link
Collaborator

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> => {
Copy link
Collaborator

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

const memberEvents = getTeamEventAttendanceByUser(member);
let approvedCount = 0;
let pendingCount = 0;
(await memberEvents).forEach((event) => {
Copy link
Collaborator

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;
    }
  });

} 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.'
Copy link
Collaborator

@andrew032011 andrew032011 Nov 8, 2023

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.

Number(event.numCredits) !== 1 ? 'credits' : 'credit'
})\n`
)
.join('')}`;
Copy link
Collaborator

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."

@andrew032011
Copy link
Collaborator

Don't send emails for non-prod environments :) (e.g. dev and staging)

Don't wanna alarm and upset anyone xD

@patriciaahuang I'll add this change in another PR: #541.

Copy link
Collaborator

@andrew032011 andrew032011 left a 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.

@patriciaahuang patriciaahuang merged commit f20b3e3 into main Nov 12, 2023
10 checks passed
@patriciaahuang patriciaahuang deleted the tec-email-reminders branch November 12, 2023 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants