feat: certificates, landing pages, ai tutor, website update, compliance

This commit is contained in:
Rotimi Best
2026-05-18 03:47:22 +01:00
parent c31ad63955
commit ac3a2c14a7
644 changed files with 56050 additions and 5439 deletions
+3
View File
@@ -21,6 +21,7 @@ export * from './student-prove-payment';
export * from './teacher-course-welcome';
export * from './student-org-invite';
export * from './student-program-welcome';
export * from './program-goal-reminder';
import type { newsfeedCommentEmail, newsfeedPostEmail } from './newsfeed';
@@ -34,6 +35,7 @@ import type { studentCourseWelcomeEmail } from './student-course-welcome';
import type { studentProvePaymentEmail } from './student-prove-payment';
import type { studentOrgInviteEmail } from './student-org-invite';
import type { studentProgramWelcomeEmail } from './student-program-welcome';
import type { programGoalReminderEmail } from './program-goal-reminder';
import type { teacherCourseWelcomeEmail } from './teacher-course-welcome';
import type { teacherStudentBuyRequestEmail } from './teacher-student-buy-request';
import type { teacherStudentJoinedEmail } from './teacher-student-joined';
@@ -63,4 +65,5 @@ export type EmailSchemas = {
teacherCourseWelcome: typeof teacherCourseWelcomeEmail.template.schema;
studentOrgInvite: typeof studentOrgInviteEmail.template.schema;
studentProgramWelcome: typeof studentProgramWelcomeEmail.template.schema;
programGoalReminder: typeof programGoalReminderEmail.template.schema;
};
@@ -0,0 +1,40 @@
import * as z from 'zod';
import { defineEmail } from '../send';
import { getDefaultTemplate } from '../templates';
export const programGoalReminderEmail = defineEmail({
id: 'programGoalReminder',
subject: 'Reminder: a program goal is due soon',
schema: z.object({
orgName: z.string().min(1),
programName: z.string().min(1),
goalTitle: z.string().min(1),
daysUntilDue: z.number().int(),
completedCount: z.number().int(),
requiredCount: z.number().int(),
loginUrl: z.string().min(1)
}),
render: (fields) => {
const dueLine =
fields.daysUntilDue <= 0
? `<p>This goal is now <strong>overdue</strong>.</p>`
: fields.daysUntilDue === 1
? `<p>This goal is due <strong>tomorrow</strong>.</p>`
: `<p>This goal is due in <strong>${fields.daysUntilDue} days</strong>.</p>`;
const progress = `${fields.completedCount} of ${fields.requiredCount} courses completed`;
const content = `
<p>Hi there,</p>
<p>This is a reminder that the goal <strong>${fields.goalTitle}</strong> in your program <strong>${fields.programName}</strong> at ${fields.orgName} needs your attention.</p>
${dueLine}
<p>Your progress so far: <strong>${progress}</strong>.</p>
<p><a href="${fields.loginUrl}">Open ClassroomIO</a> to keep going.</p>
<p>Cheers,</p>
<p>${fields.orgName}</p>
`;
return getDefaultTemplate(content);
}
});