CLASSROOMIO-T-133: Send welcome email after onboarding

Co-authored-by: Rotimi Best <rotimiibitoyeemma@gmail.com>


Merge-request: CLASSROOMIO-MR-55
Merged-by: Best Admin <best@digdippa.com>
This commit is contained in:
Rotimi Best
2023-08-26 11:58:57 +00:00
committed by Space Cloud
co-authored by Rotimi Best
parent b979da3db1
commit 7a5d341865
11 changed files with 352 additions and 45 deletions
+2
View File
@@ -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"
},
+43 -43
View File
@@ -1,47 +1,47 @@
<script>
import Avatar from '$lib/components/Avatar/index.svelte';
<script lang="ts">
import { Container, Head, Html, Img, Preview, Section, Text } from 'svelte-email';
export let children: ConstructorOfATypedSvelteComponent;
export let props = {};
const main = {
background: '#fff'
};
const container = {
margin: '20px auto 100px',
padding: '0 40px',
backgroundColor: '#fff',
width: '80%',
maxWidth: '600px'
};
const logo = {
margin: '0 auto'
};
</script>
<main>
<div class="w-full min-h-screen flex items-center justify-center">
<div class="container border border-gray bg-white">
<div class="flex items-center flex-col p-2 lg:px-8 lg:py-3">
<div class="flex items-center justify-center w-full pt-2">
<Avatar
src={'/logo-192.png'}
name={'ClassroomIO'}
shape="rounded-md"
width="w-10"
height="h-10"
className="mr-2"
<Html lang="en">
<Head />
<Preview preview="Welcome to ClassroomIO" />
<Section style={main}>
<Container style={container}>
<Img
src="https://app.classroomio.com/logo-512.png"
alt="ClassroomIO logo"
style={logo}
width="50"
height="50"
/>
<h4 class="text-xl">ClassroomIO</h4>
</div>
<div class="flex items-center flex-col w-10/12">
<h3>Welcome to ClassroomIO.</h3>
</div>
</div>
<!-- Footer -->
<div class="w-full p-6 border-t border-grey text-center">
Already have an account? <a class="hover:underline text-primary-700" href="/login">Log In</a
<Text
style={{
textAlign: 'center',
color: '#1d4ee2',
fontWeight: 'bold',
fontSize: '20px'
}}>ClassroomIO</Text
>
</div>
</div>
</div>
</main>
<style>
.container {
width: 450px;
}
main {
background: linear-gradient(
138deg,
rgb(32, 201, 255) 36.7%,
rgb(0, 8, 187) 84.4%,
rgb(255, 255, 255) 119.7%
);
box-sizing: border-box;
}
</style>
<svelte:component this={children} {...props} />
</Container>
</Section>
</Html>
+105
View File
@@ -0,0 +1,105 @@
<script lang="ts">
import { Container, Head, Hr, Html, Img, Preview, Section, Text } from 'svelte-email';
export let firstName = 'Seun';
const fontFamily =
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';
const main = {
background: `radial-gradient(
circle at 10% 20%,
rgb(239, 246, 249) 0%,
rgb(206, 239, 253) 90%
)`
};
const container = {
margin: '100px auto',
padding: '40px',
backgroundColor: '#fff',
border: '1px solid #cccccc',
borderRadius: '10px'
};
const logo = {
margin: '0 auto'
};
const paragraph = {
fontFamily,
fontSize: '16px',
lineHeight: '26px'
};
const footerParagraph = {
...paragraph,
margin: '0px'
};
const footer = {
fontFamily,
color: '#8898aa',
fontSize: '12px'
};
</script>
<Html lang="en">
<Head />
<Preview preview="Welcome to ClassroomIO" />
<Section style={main}>
<Container style={container}>
<Img
src="https://app.classroomio.com/logo-512.png"
alt="Svelte logo"
style={logo}
width="50"
height="50"
/>
<Text
style={{
textAlign: 'center',
color: '#1d4ee2',
fontWeight: 'bold',
fontSize: '20px'
}}>ClassroomIO</Text
>
<Text style={paragraph}>Dear {firstName},</Text>
<Text style={paragraph}>Welcome to the vibrant community of ClassroomIO!</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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!
</Text>
<Text style={footerParagraph}>Best regards</Text>
<Text style={footerParagraph}>Rotimi Best</Text>
<Text style={footerParagraph}>ClassroomIO</Text>
</Container>
</Section>
</Html>
+17
View File
@@ -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 <best@classroomio.com>';
export let sendgrid: MailService;
export const getSendgrid = (): MailService => {
if (sendgrid) return sendgrid;
SendGridService.setApiKey(SENDGRID_API_KEY);
sendgrid = SendGridService;
return sendgrid;
};
+7
View File
@@ -0,0 +1,7 @@
import { json } from '@sveltejs/kit';
export async function GET({ url }) {
// Get org data from request
// Get teacher email
// Generate
}
+50
View File
@@ -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'
});
}
@@ -0,0 +1,13 @@
<script lang="ts">
import EmailTemplate from '$lib/components/Email/EmailTemplate.svelte';
import Welcome from './welcome.svelte';
export let name = '';
</script>
<EmailTemplate
children={Welcome}
props={{
name
}}
/>
@@ -0,0 +1,79 @@
<script lang="ts">
import { Text, Section, Button, Link } from 'svelte-email';
export let name = '';
const fontFamily =
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';
const paragraph = {
fontFamily,
fontSize: '16px',
lineHeight: '26px'
};
const footerParagraph = {
...paragraph,
margin: '0px'
};
const btnContainer = {
textAlign: 'center' as const
};
const button = {
fontFamily,
backgroundColor: '#1d4ee2',
borderRadius: '5px',
color: '#fff',
fontSize: '16px',
textDecoration: 'none',
textAlign: 'center' as const,
display: 'block'
};
const linkStyle = {
color: '#1d4ee2'
};
</script>
<Text style={paragraph}>Dear {name},</Text>
<Text style={paragraph}>Welcome to the vibrant community of ClassroomIO!</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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.
</Text>
<Text style={paragraph}>
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!
</Text>
<Section style={btnContainer}>
<Button pX={12} pY={12} style={button} href="https://app.classroomio.com">Go to Dashboard</Button>
</Section>
<Text style={footerParagraph}>Best regards</Text>
<Text style={footerParagraph}>Rotimi Best</Text>
<Text style={footerParagraph}
><Link style={linkStyle} href="https://classroomio.com">ClassroomIO</Link></Text
>
+6
View File
@@ -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;
+28
View File
@@ -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);
}
}