From 7a5d341865807d7fdf45258db1008b8a1167464b Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Sat, 26 Aug 2023 11:58:57 +0000 Subject: [PATCH] CLASSROOMIO-T-133: Send welcome email after onboarding Co-authored-by: Rotimi Best Merge-request: CLASSROOMIO-MR-55 Merged-by: Best Admin --- package.json | 2 + src/lib/components/Email/EmailTemplate.svelte | 90 +++++++-------- src/lib/emails/Welcome.svelte | 105 ++++++++++++++++++ src/lib/utils/services/sendgrid.ts | 17 +++ src/routes/api/email/teacher/+server.js | 7 ++ src/routes/api/email/teacher/template.svelte | 0 src/routes/api/email/welcome/+server.js | 50 +++++++++ src/routes/api/email/welcome/template.svelte | 13 +++ src/routes/api/email/welcome/welcome.svelte | 79 +++++++++++++ src/routes/onboarding/+page.svelte | 6 + src/routes/onboarding/utils.ts | 28 +++++ 11 files changed, 352 insertions(+), 45 deletions(-) create mode 100644 src/lib/emails/Welcome.svelte create mode 100644 src/lib/utils/services/sendgrid.ts create mode 100644 src/routes/api/email/teacher/+server.js create mode 100644 src/routes/api/email/teacher/template.svelte create mode 100644 src/routes/api/email/welcome/+server.js create mode 100644 src/routes/api/email/welcome/template.svelte create mode 100644 src/routes/api/email/welcome/welcome.svelte create mode 100644 src/routes/onboarding/utils.ts diff --git a/package.json b/package.json index c3598a3d..3a6d8993 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.386.0", + "@sendgrid/mail": "^7.7.0", "@sentry/browser": "^7.61.0", "@sentry/integrations": "^7.61.0", "@sentry/tracing": "^7.61.0", @@ -42,6 +43,7 @@ "pluralize": "^8.0.0", "quill": "^1.3.7", "sirv": "^2.0.3", + "svelte-email": "^0.0.4", "wait-on": "^7.0.1", "zod": "^3.21.4" }, diff --git a/src/lib/components/Email/EmailTemplate.svelte b/src/lib/components/Email/EmailTemplate.svelte index 8e1254b4..5fd3da8f 100644 --- a/src/lib/components/Email/EmailTemplate.svelte +++ b/src/lib/components/Email/EmailTemplate.svelte @@ -1,47 +1,47 @@ - -
-
-
-
-
- -

ClassroomIO

-
-
-

Welcome to ClassroomIO.

-
-
- - -
- Already have an account? Log In -
-
-
-
- - + + + +
+ + ClassroomIO logo + ClassroomIO + + +
+ diff --git a/src/lib/emails/Welcome.svelte b/src/lib/emails/Welcome.svelte new file mode 100644 index 00000000..fab4e936 --- /dev/null +++ b/src/lib/emails/Welcome.svelte @@ -0,0 +1,105 @@ + + + + + +
+ + Svelte logo + ClassroomIO + Dear {firstName}, + Welcome to the vibrant community of ClassroomIO! + + We're thrilled to have you join us in shaping the future of education. Your decision to + embark on this journey with us is deeply appreciated, and we're genuinely excited about the + possibilities that lie ahead. + + + At ClassroomIO, we understand the dedication and passion that educators like you bring to + the table. That's why we've built a platform that's not only designed to make your teaching + experience seamless but also to empower you to create transformative learning moments for + your students. + + + Your choice to use ClassroomIO is a testament to your commitment to innovation in education. + It's educators like you who drive progress and inspire change, and we're here to support you + every step of the way. + + + Our team is working diligently behind the scenes, shipping new features and updates daily. + This means you can expect a platform that's constantly evolving, adapting to your needs, and + staying at the forefront of educational technology. + + + We encourage you to explore ClassroomIO's range of features, from interactive quizzes and + robust course management tools to collaborative forums and AI-integrated lesson planning. + Your feedback is invaluable to us as we work together to refine and enhance these features + to best suit your teaching style and objectives. + + + Once again, welcome to the ClassroomIO family. We're here to help, to listen, and to + celebrate your successes. Get ready to unlock a world of possibilities in education! + + Best regards + Rotimi Best + ClassroomIO + +
+ diff --git a/src/lib/utils/services/sendgrid.ts b/src/lib/utils/services/sendgrid.ts new file mode 100644 index 00000000..8d4ccb9d --- /dev/null +++ b/src/lib/utils/services/sendgrid.ts @@ -0,0 +1,17 @@ +import * as SendGridService from '@sendgrid/mail'; +import type { MailService } from '@sendgrid/mail'; +import { SENDGRID_API_KEY } from '$env/static/private'; + +export const SENDGRID_FROM = 'Rotimi Best '; + +export let sendgrid: MailService; + +export const getSendgrid = (): MailService => { + if (sendgrid) return sendgrid; + + SendGridService.setApiKey(SENDGRID_API_KEY); + + sendgrid = SendGridService; + + return sendgrid; +}; diff --git a/src/routes/api/email/teacher/+server.js b/src/routes/api/email/teacher/+server.js new file mode 100644 index 00000000..cceaaabe --- /dev/null +++ b/src/routes/api/email/teacher/+server.js @@ -0,0 +1,7 @@ +import { json } from '@sveltejs/kit'; + +export async function GET({ url }) { + // Get org data from request + // Get teacher email + // Generate +} diff --git a/src/routes/api/email/teacher/template.svelte b/src/routes/api/email/teacher/template.svelte new file mode 100644 index 00000000..e69de29b diff --git a/src/routes/api/email/welcome/+server.js b/src/routes/api/email/welcome/+server.js new file mode 100644 index 00000000..14001814 --- /dev/null +++ b/src/routes/api/email/welcome/+server.js @@ -0,0 +1,50 @@ +import { render } from 'svelte-email'; +import { json } from '@sveltejs/kit'; +import WelcomeTemplate from './template.svelte'; +import { getSendgrid, SENDGRID_FROM } from '$lib/utils/services/sendgrid'; +import { getSupabase } from '$lib/utils/functions/supabase'; + +const sendgrid = getSendgrid(); +const supabase = getSupabase(); + +export async function POST({ request }) { + const { to, name } = await request.json(); + const accessToken = request.headers.get('Authorization'); + console.log('/POST api/email/welcome', to, name); + + if (!to || !name) { + return json({ success: false, message: 'Name and To are required fields' }, { status: 400 }); + } + + let user; + try { + const { data } = await supabase.auth.getUser(accessToken); + user = data.user; + } catch (error) { + console.error(error); + } + + console.log('user', user); + if (!user) { + return json({ success: false, message: 'Unauthenticated user' }, { status: 401 }); + } + + const options = { + from: SENDGRID_FROM, + to, + subject: 'Thank you so so so much for choosing ClassroomIO!', + html: render({ + template: WelcomeTemplate, + props: { + name + } + }) + }; + + sendgrid.send(options); + + return json({ + success: true, + message: 'Email sent' + }); +} diff --git a/src/routes/api/email/welcome/template.svelte b/src/routes/api/email/welcome/template.svelte new file mode 100644 index 00000000..aed13b4a --- /dev/null +++ b/src/routes/api/email/welcome/template.svelte @@ -0,0 +1,13 @@ + + + diff --git a/src/routes/api/email/welcome/welcome.svelte b/src/routes/api/email/welcome/welcome.svelte new file mode 100644 index 00000000..40149e0c --- /dev/null +++ b/src/routes/api/email/welcome/welcome.svelte @@ -0,0 +1,79 @@ + + +Dear {name}, +Welcome to the vibrant community of ClassroomIO! + + We're thrilled to have you join us in shaping the future of education. Your decision to embark on + this journey with us is deeply appreciated, and we're genuinely excited about the possibilities + that lie ahead. + + + At ClassroomIO, we understand the dedication and passion that educators like you bring to the + table. That's why we've built a platform that's not only designed to make your teaching experience + seamless but also to empower you to create transformative learning moments for your students. + + + Your choice to use ClassroomIO is a testament to your commitment to innovation in education. It's + educators like you who drive progress and inspire change, and we're here to support you every step + of the way. + + + Our team is working diligently behind the scenes, shipping new features and updates daily. This + means you can expect a platform that's constantly evolving, adapting to your needs, and staying at + the forefront of educational technology. + + + We encourage you to explore ClassroomIO's range of features, from interactive quizzes and robust + course management tools to collaborative forums and AI-integrated lesson planning. Your feedback + is invaluable to us as we work together to refine and enhance these features to best suit your + teaching style and objectives. + + + Once again, welcome to the ClassroomIO family. We're here to help, to listen, and to celebrate + your successes. Get ready to unlock a world of possibilities in education! + +
+ +
+Best regards +Rotimi Best +ClassroomIO diff --git a/src/routes/onboarding/+page.svelte b/src/routes/onboarding/+page.svelte index d8ab1bbf..fc9913d1 100644 --- a/src/routes/onboarding/+page.svelte +++ b/src/routes/onboarding/+page.svelte @@ -10,6 +10,7 @@ import { blockedSubdomain } from '$lib/utils/constants/app'; import { welcomeModalStore } from '$lib/components/WelcomeModal/store'; import { getOrganizations } from '$lib/utils/services/org'; + import { sendWelcomeEmail } from './utils'; interface OnboardingField { fullname?: string; @@ -80,6 +81,7 @@ const payload = await response.json(); fields.metadata = payload; } + function setOrgSiteName(orgName: string | undefined, isTouched: boolean) { if (!orgName || isTouched) return; let inputElement = event?.target as HTMLInputElement; @@ -177,6 +179,10 @@ .match({ id: $profile.id }); loading = false; + if (fields.fullname) { + sendWelcomeEmail($profile.email, fields.fullname); + } + console.log('data', data); console.log('error', error); $welcomeModalStore.open = true; diff --git a/src/routes/onboarding/utils.ts b/src/routes/onboarding/utils.ts new file mode 100644 index 00000000..f0d5c16a --- /dev/null +++ b/src/routes/onboarding/utils.ts @@ -0,0 +1,28 @@ +import { supabase } from '$lib/utils/functions/supabase'; + +export async function sendWelcomeEmail(to: string, name: string) { + const { data } = await supabase.auth.getSession(); + const accessToken = data.session?.access_token || ''; + + try { + const response = await fetch('/api/email/welcome', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: accessToken + }, + body: JSON.stringify({ + to, + name + }) + }); + if (!response.ok) { + throw new Error(await response.text()); + } + const result = await response.json(); + + console.log('Sent confirmation email', result); + } catch (error) { + console.error('Error sending confirmation email', error); + } +}