Skip to content

Commit d547626

Browse files
committed
add admin emailing and mark placeholders
1 parent 6c6ef22 commit d547626

File tree

5 files changed

+79
-28
lines changed

5 files changed

+79
-28
lines changed

backend/typescript/rest/camperRoutes.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,12 @@ import CamperService from "../services/implementations/camperService";
1212
import ICamperService from "../services/interfaces/camperService";
1313
import { getErrorMessage } from "../utilities/errorUtils";
1414
import { sendResponseByMimeType } from "../utilities/responseUtil";
15-
import { CamperDTO, CreateCampersDTO, WaitlistedCamperDTO } from "../types";
15+
import {
16+
CamperDTO,
17+
CreateCampersDTO,
18+
EmailDTO,
19+
WaitlistedCamperDTO,
20+
} from "../types";
1621
import { createWaitlistedCamperDtoValidator } from "../middlewares/validators/waitlistedCamperValidators";
1722
import IEmailService from "../services/interfaces/emailService";
1823
import EmailService from "../services/implementations/emailService";
@@ -22,17 +27,17 @@ const camperRouter: Router = Router();
2227

2328
const camperService: ICamperService = new CamperService();
2429

25-
const emailService: IEmailService = new EmailService(nodemailerConfig);
26-
2730
// ROLES: Leaving unprotected as the registration flow probs needs this endpoint to register @dhruv
2831
/* Create a camper */
2932
camperRouter.post("/register", createCampersDtoValidator, async (req, res) => {
3033
try {
3134
const campers = req.body.campers as CreateCampersDTO;
3235
const campSessions = req.body.campSessions as string[];
36+
const waiverContent = req.body.waiverContent as EmailDTO;
3337
const newCampers = await camperService.createCampers(
3438
campers,
3539
campSessions,
40+
waiverContent,
3641
req.query?.wId as string,
3742
);
3843
res.status(201).json(newCampers);
@@ -41,16 +46,6 @@ camperRouter.post("/register", createCampersDtoValidator, async (req, res) => {
4146
}
4247
});
4348

44-
camperRouter.post("/email", async (req, res) => {
45-
try {
46-
const waiverContent = req.body;
47-
emailService.sendWaiverEmail(waiverContent);
48-
res.status(201);
49-
} catch (error: unknown) {
50-
res.status(500).json({ error: getErrorMessage(error) });
51-
}
52-
});
53-
5449
// ROLES: Admin + CC
5550
/* Get all campers, optionally filter by camp ID */
5651
camperRouter.get(

backend/typescript/services/implementations/camperService.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
WaitlistedCamperDTO,
1515
UpdateCamperDTO,
1616
CamperCharges,
17+
EmailDTO,
1718
} from "../../types";
1819
import { getErrorMessage } from "../../utilities/errorUtils";
1920
import logger from "../../utilities/logger";
@@ -80,7 +81,7 @@ class CamperService implements ICamperService {
8081
async createCampers(
8182
campers: CreateCampersDTO,
8283
campSessions: string[],
83-
waiverContent: string,
84+
waiverContent: EmailDTO,
8485
waitlistedCamperId?: string,
8586
): Promise<CamperDTO[]> {
8687
const session = await mongoose.startSession();
@@ -246,10 +247,11 @@ class CamperService implements ICamperService {
246247
);
247248

248249
// Email the parent about all the campers and sessions they have signed up for
249-
await emailService.sendRegistrationEmails(
250+
await emailService.sendConfirmationEmails(
250251
camp,
251252
registeredCampers,
252253
sessionsToRegister,
254+
waiverContent,
253255
);
254256

255257
// Send admin an email for all the sessions that are now full
@@ -449,7 +451,10 @@ class CamperService implements ICamperService {
449451
): Promise<CamperDTO[]> {
450452
try {
451453
// eslint-disable-next-line prettier/prettier
452-
const campers: Camper[] = await MgCamper.find({ chargeId, campSession: sessionId });
454+
const campers: Camper[] = await MgCamper.find({
455+
chargeId,
456+
campSession: sessionId,
457+
});
453458

454459
if (!campers || campers.length === 0) {
455460
throw new Error(

backend/typescript/services/implementations/emailService.ts

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { CampSession } from "../../models/campSession.model";
1010
import { WaitlistedCamper } from "../../models/waitlistedCamper.model";
1111

1212
// TODO: swap out this email for the focus on nature admin email
13-
const ADMIN_EMAIL = "focusonnature@uwblueprint.org";
13+
const ADMIN_EMAIL = "camps@focusonnature.ca";
1414

1515
const Logger = logger(__filename);
1616

@@ -48,26 +48,71 @@ class EmailService implements IEmailService {
4848
}
4949
}
5050

51-
async sendWaiverEmail(waiverContent: EmailDTO): Promise<void> {
51+
async sendConfirmationEmails(
52+
camp: Camp,
53+
campers: Camper[],
54+
campSessions: CampSession[],
55+
waiverContent: EmailDTO,
56+
): Promise<void> {
5257
const pdfAttachment: Attachment = {
5358
filename: "waiver.pdf",
5459
content: Buffer.from(waiverContent.pdf),
5560
contentType: "application/pdf",
5661
encoding: "base64",
5762
};
5863

64+
await this.sendAdminConfirmationEmail(camp, campers, campSessions, [
65+
pdfAttachment,
66+
]);
67+
68+
await this.sendParentConfirmationEmail(camp, campers, campSessions, [
69+
pdfAttachment,
70+
]);
71+
}
72+
73+
async sendAdminConfirmationEmail(
74+
camp: Camp,
75+
campers: Camper[],
76+
campSessions: CampSession[],
77+
attachments: Attachment[],
78+
): Promise<void> {
79+
const sessionDatesListItems: string[] = getSessionDatesListItems(
80+
campSessions,
81+
);
82+
5983
await this.sendEmail(
60-
"bowenzhu@uwblueprint.org",
61-
"Focus on Nature Camp Registration - Waiver",
62-
"A copy of your Focus on Nature Camp Registration is attached.",
63-
[pdfAttachment],
84+
ADMIN_EMAIL,
85+
`Waiver Responses for
86+
${campers.map((camper) => {
87+
return `${camper.firstName} ${camper.lastName},`;
88+
})}
89+
for ${camp.name}`,
90+
`<ul>
91+
<li><b>Campers:</b></li>
92+
${campers
93+
.map((camper) => {
94+
return `<ul>
95+
<li><b>Name:</b> ${camper.firstName} ${camper.lastName}</li>
96+
<ul><li><b>Age:</b> ${camper.age}</li></ul>
97+
</ul>`;
98+
})
99+
.join("")}
100+
<li><b>Camp name:</b> ${camp.name}</li>
101+
<li><b>Session dates:</b></li>
102+
<ol>
103+
${sessionDatesListItems.join("")}
104+
</ol>
105+
<li><b>Responses Received on:</b> </li>
106+
</ul>`,
107+
attachments,
64108
);
65109
}
66110

67111
async sendParentConfirmationEmail(
68112
camp: Camp,
69113
campers: Camper[],
70114
campSessions: CampSession[],
115+
attachments: Attachment[],
71116
): Promise<void> {
72117
const contact = campers[0].contacts[0];
73118
const link = "DUMMY LINK"; // TODO: Update link
@@ -147,6 +192,7 @@ class EmailService implements IEmailService {
147192
if we have another camper on our waitlist.
148193
<br><br>Thanks, <br><br>
149194
Focus on Nature`,
195+
attachments,
150196
);
151197
}
152198

backend/typescript/services/interfaces/camperService.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
CreateWaitlistedCamperDTO,
55
WaitlistedCamperDTO,
66
UpdateCamperDTO,
7+
EmailDTO,
78
} from "../../types";
89

910
interface ICamperService {
@@ -19,7 +20,7 @@ interface ICamperService {
1920
createCampers(
2021
campers: CreateCampersDTO,
2122
campSessions: string[],
22-
waiverContent: string,
23+
waiverContent: EmailDTO,
2324
waitlistedCamperId?: string,
2425
): Promise<CamperDTO[]>;
2526

backend/typescript/services/interfaces/emailService.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,43 @@
1+
import { Attachment } from "nodemailer/lib/mailer";
12
import { Camp } from "../../models/camp.model";
23
import { Camper } from "../../models/camper.model";
34
import { CampSession } from "../../models/campSession.model";
45
import { WaitlistedCamper } from "../../models/waitlistedCamper.model";
6+
import { EmailDTO } from "../../types";
57

68
interface IEmailService {
79
/**
8-
* Send camp registration confirmation email.
10+
* Wrapper to send camp registration confirmation emails
11+
* to admin and parents with waiver pdf attached.
912
* @throws Error if email was not sent successfully
1013
*/
1114
sendConfirmationEmails(
1215
camp: Camp,
1316
campers: Camper[],
1417
campSessions: CampSession[],
15-
waiverContent: string,
18+
waiverContent: EmailDTO,
1619
): Promise<void>;
1720

1821
/**
19-
* Send camp registration confirmation email.
22+
* Send camp registration confirmation email to admin.
2023
* @throws Error if email was not sent successfully
2124
*/
2225
sendAdminConfirmationEmail(
2326
camp: Camp,
2427
campers: Camper[],
2528
campSessions: CampSession[],
26-
waiverContent: string,
29+
attachments: Attachment[],
2730
): Promise<void>;
2831

2932
/**
30-
* Send camp registration confirmation email.
33+
* Send camp registration confirmation email to parent.
3134
* @throws Error if email was not sent successfully
3235
*/
3336
sendParentConfirmationEmail(
3437
camp: Camp,
3538
campers: Camper[],
3639
campSessions: CampSession[],
40+
attachments: Attachment[],
3741
): Promise<void>;
3842

3943
/**

0 commit comments

Comments
 (0)