CLASSROOMIO-T-152: Landing page fully ready

This commit is contained in:
Rotimi Best
2023-09-15 08:26:26 +01:00
parent 90274d7ef4
commit 6db697bc6c
18 changed files with 510 additions and 70 deletions
@@ -0,0 +1,60 @@
import { render } from 'svelte-email';
import { json } from '@sveltejs/kit';
import JoinRequestTemplate from './template.svelte';
import { getSendgrid, SENDGRID_FROM_NOREPLY } 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, courseName, teacherEmail, studentFullname, orgName } = await request.json();
const accessToken = request.headers.get('Authorization') || '';
console.log(
'/POST api/email/course/student_prove_payment',
to,
courseName,
teacherEmail,
studentFullname,
orgName
);
if (!to || !courseName || !teacherEmail || !studentFullname || !orgName) {
return json({ success: false, message: 'Missing required fields' }, { status: 400 });
}
let user;
try {
const { data } = await supabase.auth.getUser(accessToken);
user = data.user;
} catch (error) {
console.error(error);
}
if (!user) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
const options = {
from: SENDGRID_FROM_NOREPLY,
to,
replyTo: teacherEmail,
subject: `[${courseName}] One more step left`,
html: render({
template: JoinRequestTemplate,
props: {
courseName,
studentFullname,
teacherEmail,
orgName
}
})
};
sendgrid.send(options);
return json({
success: true,
message: 'Email sent'
});
}
@@ -0,0 +1,37 @@
<script lang="ts">
import { Text } from 'svelte-email';
export let courseName = '';
export let studentFullname = '';
export let teacherEmail = '';
export let orgName = '';
const fontFamily =
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';
const paragraph = {
fontFamily,
fontSize: '16px',
lineHeight: '26px'
};
const paragraphContent = {
...paragraph,
margin: '20px 0'
};
const footerParagraph = {
...paragraph,
margin: '0px'
};
</script>
<Text style={paragraph}>Hi {studentFullname},</Text>
<Text style={paragraphContent}>
You are one step closer to joining: {courseName}
</Text>
<Text style={paragraphContent}>
Please send your proof of payment to: {teacherEmail}, in order to join the course.
</Text>
<Text style={footerParagraph}>Talk to you soon and see you in class.</Text>
<Text style={footerParagraph}>{orgName}</Text>
@@ -0,0 +1,19 @@
<script lang="ts">
import EmailTemplate from '$lib/components/Email/EmailTemplate.svelte';
import ProvePayment from './prove_payment.svelte';
export let courseName = '';
export let studentFullname = '';
export let orgName = '';
export let teacherEmail = '';
</script>
<EmailTemplate
children={ProvePayment}
props={{
courseName,
studentFullname,
orgName,
teacherEmail
}}
/>
@@ -0,0 +1,57 @@
import { render } from 'svelte-email';
import { json } from '@sveltejs/kit';
import JoinRequestTemplate from './template.svelte';
import { getSendgrid, SENDGRID_FROM_NOREPLY } 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, courseName, studentEmail, studentFullname } = await request.json();
const accessToken = request.headers.get('Authorization') || '';
console.log(
'/POST api/email/course/teacher_student_buycourse',
to,
courseName,
studentEmail,
studentFullname
);
if (!to || !courseName || !studentEmail || !studentFullname) {
return json({ success: false, message: 'Missing required fields' }, { status: 400 });
}
let user;
try {
const { data } = await supabase.auth.getUser(accessToken);
user = data.user;
} catch (error) {
console.error(error);
}
if (!user) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
const options = {
from: SENDGRID_FROM_NOREPLY,
to,
subject: `[${courseName}] Request to Join Course!`,
html: render({
template: JoinRequestTemplate,
props: {
courseName,
studentFullname,
studentEmail
}
})
};
sendgrid.send(options);
return json({
success: true,
message: 'Email sent'
});
}
@@ -0,0 +1,44 @@
<script lang="ts">
import { Text, Link } from 'svelte-email';
export let courseName = '';
export let studentFullname = '';
export let studentEmail = '';
const fontFamily =
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';
const paragraph = {
fontFamily,
fontSize: '16px',
lineHeight: '26px'
};
const paragraphContent = {
...paragraph,
margin: '20px 0'
};
const footerParagraph = {
...paragraph,
margin: '0px'
};
const linkStyle = {
color: '#1d4ee2'
};
</script>
<Text style={paragraph}>Hi amazing tutor,</Text>
<Text style={paragraphContent}>
A new student has requested to join a course you are teaching: “{courseName}"
</Text>
<Text style={paragraphContent}>Student details</Text>
<Text style={paragraphContent}>
Name: {studentFullname}<br />
Email: {studentEmail}
</Text>
<Text style={footerParagraph}>Cheers</Text>
<Text style={footerParagraph}>
<Link style={linkStyle} href="https://classroomio.com">ClassroomIO</Link>
</Text>
@@ -0,0 +1,17 @@
<script lang="ts">
import EmailTemplate from '$lib/components/Email/EmailTemplate.svelte';
import JoinRequest from './join_request.svelte';
export let courseName = '';
export let studentFullname = '';
export let studentEmail = '';
</script>
<EmailTemplate
children={JoinRequest}
props={{
courseName,
studentFullname,
studentEmail
}}
/>
@@ -28,7 +28,7 @@
<Text style={paragraph}>Hi amazing tutor,</Text>
<Text style={paragraphContent}>
Congratulations, a new student has joined a course you are teaching: “{courseName}""
Congratulations, a new student has joined a course you are teaching: “{courseName}"
</Text>
<Text style={paragraphContent}>
We hope they have a great experience learning from the best (YOU).
+11 -1
View File
@@ -1,5 +1,15 @@
export const load = ({ params = { slug: '' } }) => {
import { fetchCourse } from '$lib/utils/services/courses';
import { supabase, getSupabase } from '$lib/utils/functions/supabase';
if (!supabase) {
getSupabase();
}
export const load = async ({ params = { slug: '' } }) => {
const { data } = await fetchCourse(undefined, params.slug);
return {
slug: params.slug,
course: data
};
};
+13 -31
View File
@@ -1,39 +1,21 @@
<script>
import Backdrop from '$lib/components/Backdrop/index.svelte';
import { Moon } from 'svelte-loading-spinners';
<script lang="ts">
import CourseLandingPage from '$lib/components/CourseLandingPage/index.svelte';
import { profile } from '$lib/utils/store/user';
import { setCourse, course } from '$lib/components/Course/store';
import { lessons } from '$lib/components/Course/components/Lesson/store/lessons';
import { fetchCourse } from '$lib/utils/services/courses';
import { browser } from '$app/environment';
import type { Course } from '$lib/utils/types';
export let data;
interface Data {
course: Course;
}
export let data: Data;
let courseData = {};
let loading = false;
let courseData: Course;
async function triggerSetCourse(_profile) {
if (!browser) return;
loading = true;
const { data: _data } = await fetchCourse(undefined, data.slug);
setCourse(_data);
loading = false;
function setCourseData(course: Course | null) {
if (!course) return;
courseData = { ...course };
}
function setCourseData(course, lessons) {
courseData = { ...course, lessons };
console.log('courseData', courseData);
}
$: triggerSetCourse($profile);
$: setCourseData($course, $lessons);
$: setCourseData(data.course);
</script>
{#if loading}
<Backdrop>
<Moon size="60" color="#1d4ed8" unit="px" duration="1s" />
</Backdrop>
{:else}
<CourseLandingPage {courseData} />
{/if}
<CourseLandingPage {courseData} />
+22 -3
View File
@@ -16,6 +16,7 @@
let supabase = getSupabase();
let loading = false;
let refresh = false;
let disableSubmit = false;
let formRef: HTMLFormElement;
@@ -23,6 +24,18 @@
async function handleSubmit() {
loading = true;
if (refresh) {
window.location.reload();
refresh = false;
return;
}
if (!$profile.id || !$profile.email) {
console.log('Profile not found', $profile);
refresh = true;
return;
}
const member = {
profile_id: $profile.id,
group_id: data.groupId,
@@ -91,13 +104,19 @@
bind:formRef
>
<div class="mt-0 w-full">
<h3 class="dark:text-white text-lg font-medium mt-0 mb-4 text-center">{data.name}</h3>
<p class="dark:text-white text-sm font-light text-center">{data.description}</p>
{#if refresh}
<p class="dark:text-white text-sm font-light text-center">
Something went wrong, please try again.
</p>
{:else}
<h3 class="dark:text-white text-lg font-medium mt-0 mb-4 text-center">{data.name}</h3>
<p class="dark:text-white text-sm font-light text-center">{data.description}</p>
{/if}
</div>
<div class="my-4 w-full flex justify-center items-center">
<PrimaryButton
label="Join Course"
label={refresh ? 'Try again' : 'Join Course'}
type="submit"
isDisabled={disableSubmit || loading}
isLoading={loading}