diff --git a/apps/dashboard/src/lib/components/Course/components/Lesson/Materials/index.svelte b/apps/dashboard/src/lib/components/Course/components/Lesson/Materials/index.svelte
index 7f30cd2e..da44ccfa 100644
--- a/apps/dashboard/src/lib/components/Course/components/Lesson/Materials/index.svelte
+++ b/apps/dashboard/src/lib/components/Course/components/Lesson/Materials/index.svelte
@@ -1,5 +1,4 @@
{#if name === 'Overview'}
+{:else if name === 'News Feed'}
+
{:else if name === 'Lessons'}
{:else if name === 'Attendance'}
diff --git a/apps/dashboard/src/lib/components/Course/components/Navigation/index.svelte b/apps/dashboard/src/lib/components/Course/components/Navigation/index.svelte
index ed9f9e4f..405a2628 100644
--- a/apps/dashboard/src/lib/components/Course/components/Navigation/index.svelte
+++ b/apps/dashboard/src/lib/components/Course/components/Navigation/index.svelte
@@ -146,7 +146,7 @@
$: {
navItems = [
{
- label: 'Overview',
+ label: 'News Feed',
to: getNavItemRoute($course.id),
hideSortIcon: true
},
@@ -207,8 +207,6 @@
}
];
}
-
- $: console.log({ isStudent: $globalStore.isStudent });
-
-
-
-
- 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/apps/dashboard/src/lib/utils/functions/course.ts b/apps/dashboard/src/lib/utils/functions/course.ts
index 93eff702..a5d4ceb9 100644
--- a/apps/dashboard/src/lib/utils/functions/course.ts
+++ b/apps/dashboard/src/lib/utils/functions/course.ts
@@ -17,13 +17,6 @@ export const getStudentInviteLink = (_course: Course, orgSiteName: string, origi
return `${origin}/invite/s/${hash}`;
};
-export const getTextFromHTML = (html: string): string => {
- const dummyDiv = document.createElement('div');
- dummyDiv.innerHTML = html;
-
- return dummyDiv.textContent?.trim() || '';
-};
-
const tagsToReplace: { [k: string]: string } = {
'&': '&',
'<': '<',
diff --git a/apps/dashboard/src/lib/utils/functions/toHtml.js b/apps/dashboard/src/lib/utils/functions/toHtml.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/apps/dashboard/src/lib/utils/functions/toHtml.ts b/apps/dashboard/src/lib/utils/functions/toHtml.ts
new file mode 100644
index 00000000..e8384112
--- /dev/null
+++ b/apps/dashboard/src/lib/utils/functions/toHtml.ts
@@ -0,0 +1,16 @@
+import { browser } from '$app/environment';
+
+export const isHtmlValueEmpty = (html: string) => {
+ if (!html || typeof html !== 'string') return true;
+
+ if (!document || !browser) return false;
+
+ return getTextFromHTML(html) === '';
+};
+
+export const getTextFromHTML = (html: string): string => {
+ const dummyDiv = document.createElement('div');
+ dummyDiv.innerHTML = html;
+
+ return dummyDiv.textContent?.trim() || '';
+};
diff --git a/apps/dashboard/src/lib/utils/services/courses/clone.ts b/apps/dashboard/src/lib/utils/services/courses/clone.ts
index d1c1b6a9..605732cf 100644
--- a/apps/dashboard/src/lib/utils/services/courses/clone.ts
+++ b/apps/dashboard/src/lib/utils/services/courses/clone.ts
@@ -228,7 +228,6 @@ export async function cloneCourse(courseId: string, newTitle: string): Promise
Note the following information will be copied
3. Things to copy
-Overview
Lessons
Exercises - questions, options, everything basically.
diff --git a/apps/dashboard/src/lib/utils/services/courses/index.ts b/apps/dashboard/src/lib/utils/services/courses/index.ts
index bda78fa2..a4d25e9b 100644
--- a/apps/dashboard/src/lib/utils/services/courses/index.ts
+++ b/apps/dashboard/src/lib/utils/services/courses/index.ts
@@ -142,6 +142,10 @@ export function addGroupMember(member: any) {
return supabase.from('groupmember').insert(member).select();
}
+export function addDefaultNewsFeed(feed) {
+ return supabase.from('course_newsfeed').insert(feed);
+}
+
export function updatedGroupMember(update: any, match: any) {
return supabase.from('groupmember').update(update).match(match);
}
diff --git a/apps/dashboard/src/lib/utils/services/newsfeed/index.ts b/apps/dashboard/src/lib/utils/services/newsfeed/index.ts
new file mode 100644
index 00000000..f921a000
--- /dev/null
+++ b/apps/dashboard/src/lib/utils/services/newsfeed/index.ts
@@ -0,0 +1,181 @@
+import type { Course } from '$lib/utils/types';
+import { supabase } from '$lib/utils/functions/supabase';
+import type { Reaction, FeedApi } from '$lib/utils/types/feed';
+
+export async function fetchNewsFeeds(courseId?: Course['id']) {
+ const response = await supabase
+ .from('course_newsfeed')
+ .select(
+ `
+ id,
+ created_at,
+ content,
+ course_id,
+ author:groupmember(
+ profile(
+ id,
+ fullname,
+ avatar_url
+ )
+ ),
+ reaction,
+ is_pinned,
+ comment:course_newsfeed_comment(
+ id,
+ created_at,
+ author:groupmember( profile(id, fullname, avatar_url) ),
+ content,
+ course_newsfeed_id)
+ `
+ )
+ .match({ course_id: courseId })
+ .order('created_at', { ascending: false })
+ .returns();
+
+ const { data, error } = response;
+
+ return { data, error };
+}
+
+export async function createNewFeed(post: {
+ content: string;
+ author_id: string;
+ course_id: string;
+ reaction: Reaction;
+}) {
+ const response = await supabase
+ .from('course_newsfeed')
+ .insert({
+ content: post.content,
+ author_id: post.author_id,
+ course_id: post.course_id,
+ reaction: post.reaction
+ })
+ .select();
+
+ return { response };
+}
+
+export async function handleEditFeed(feedId: string, content: string) {
+ const response = await supabase
+ .from('course_newsfeed')
+ .update({ content: content })
+ .match({ id: feedId })
+ .select();
+ return response;
+}
+
+export async function createComment(comment: {
+ content: string;
+ author_id: string;
+ course_newsfeed_id: string;
+}) {
+ const response = await supabase
+ .from('course_newsfeed_comment')
+ .insert({
+ content: comment.content,
+ author_id: comment.author_id,
+ course_newsfeed_id: comment.course_newsfeed_id
+ })
+ .select();
+
+ return { response };
+}
+
+export async function toggleFeedIsPinned(feedId: string, isPinned: boolean) {
+ const response = await supabase
+ .from('course_newsfeed')
+ .update({
+ is_pinned: isPinned
+ })
+ .match({ id: feedId });
+
+ return { response };
+}
+
+export async function deleteNewsFeedComment(commentId: string) {
+ const response = await supabase.from('course_newsfeed_comment').delete().match({ id: commentId });
+
+ return response;
+}
+export async function deleteNewsFeed(feedId: string) {
+ await supabase.from('course_newsfeed_comment').delete().match({ course_newsfeed_id: feedId });
+ const response = await supabase.from('course_newsfeed').delete().match({ id: feedId });
+
+ return response;
+}
+
+export async function getFeedForNotification(feedId: string, authorId: string) {
+ const { data, error } = await supabase
+ .from('course_newsfeed')
+ .select(
+ `
+ content,
+ author:groupmember(profile(fullname, email)),
+ course(
+ id,
+ title,
+ group(
+ organization(siteName, name),
+ members:groupmember(id, profile(email, fullname))
+ )
+ )
+ `
+ )
+ .eq('id', feedId)
+ .limit(1)
+ .returns<
+ {
+ content: string;
+ author: {
+ profile: {
+ email: string;
+ fullname: string;
+ };
+ };
+ course: {
+ id: string;
+ title: string;
+ group: {
+ organization: {
+ name: string;
+ siteName: string;
+ };
+ members: {
+ id: string;
+ profile: {
+ email: string;
+ fullname: string;
+ };
+ }[];
+ };
+ };
+ }[]
+ >();
+
+ if (error) {
+ console.error('Failed to get feed', error);
+ return null;
+ }
+ console.log({
+ data
+ });
+ const [feed] = data || [];
+
+ if (!feed) return;
+
+ return {
+ id: feedId,
+ courseId: feed.course.id,
+ courseTitle: feed.course.title,
+ teacherName: feed.author?.profile?.fullname,
+ teacherEmail: feed.author?.profile?.email,
+ content: feed.content,
+ org: feed.course.group?.organization,
+ courseMembers: feed.course?.group?.members
+ ?.filter((member) => member.id !== authorId)
+ ?.map((member) => {
+ return member.profile;
+ })
+ };
+}
diff --git a/apps/dashboard/src/lib/utils/services/notification/notification.ts b/apps/dashboard/src/lib/utils/services/notification/notification.ts
index 24449269..bd756da8 100644
--- a/apps/dashboard/src/lib/utils/services/notification/notification.ts
+++ b/apps/dashboard/src/lib/utils/services/notification/notification.ts
@@ -9,7 +9,8 @@ export const NOTIFICATION_NAME = {
STUDENT_COURSE_WELCOME: 'STUDENT COURSE WELCOME',
TEACHER_STUDENT_JOINED: 'TEACHER STUDENT JOINED',
SUBMISSION_UPDATE: 'SUBMISSION UPDATE',
- EXERCISE_SUBMISSION_UPDATE: 'EXERCISE SUBMISSION UPDATE'
+ EXERCISE_SUBMISSION_UPDATE: 'EXERCISE SUBMISSION UPDATE',
+ NEWSFEED: 'NEWSFEED'
};
const NAME_TO_PATH = {
@@ -22,7 +23,8 @@ const NAME_TO_PATH = {
[NOTIFICATION_NAME.STUDENT_COURSE_WELCOME]: '/api/email/course/student_welcome',
[NOTIFICATION_NAME.TEACHER_STUDENT_JOINED]: '/api/email/course/teacher_student_joined',
[NOTIFICATION_NAME.SUBMISSION_UPDATE]: '/api/email/course/submission_update',
- [NOTIFICATION_NAME.EXERCISE_SUBMISSION_UPDATE]: '/api/email/course/exercise_submission_update'
+ [NOTIFICATION_NAME.EXERCISE_SUBMISSION_UPDATE]: '/api/email/course/exercise_submission_update',
+ [NOTIFICATION_NAME.NEWSFEED]: '/api/email/course/newsfeed'
};
const getAccessToken = async () => {
@@ -30,7 +32,7 @@ const getAccessToken = async () => {
return data.session?.access_token || '';
};
-export const triggerSendEmail = async (name: string, body: { [k: string]: any }) => {
+export const triggerSendEmail = async (name: string, body: { [k: string]: unknown }) => {
try {
const accessToken = await getAccessToken();
const path = NAME_TO_PATH[name];
@@ -51,7 +53,6 @@ export const triggerSendEmail = async (name: string, body: { [k: string]: any })
console.log(response);
throw new Error(await response.text());
}
- const result = await response.json();
} catch (error) {
console.error(name, error);
}
diff --git a/apps/dashboard/src/lib/utils/services/notification/send.ts b/apps/dashboard/src/lib/utils/services/notification/send.ts
index 9496c38b..b038b4f4 100644
--- a/apps/dashboard/src/lib/utils/services/notification/send.ts
+++ b/apps/dashboard/src/lib/utils/services/notification/send.ts
@@ -4,21 +4,10 @@ import {
SMTP_HOST,
SMTP_USER,
SMTP_PASSWORD,
- SMTP_USER_HELP,
- SMTP_PASSWORD_HELP
+ SMTP_USER_NOTIFY,
+ SMTP_PASSWORD_NOTIFY
} from '$env/static/private';
-const content = `
-
-
Welcome
-
-
Thank you so much for trying out ClassroomIO
-
Login
-
-Your ClassroomIO Team
-
-`;
-
let transporter: nodemailer.Transporter;
const getTransporter = async (isPersonal?: boolean): Promise => {
@@ -28,8 +17,8 @@ const getTransporter = async (isPersonal?: boolean): Promise => {
port: 465,
secure: true,
auth: {
- user: isPersonal ? SMTP_USER : SMTP_USER_HELP,
- pass: isPersonal ? SMTP_PASSWORD : SMTP_PASSWORD_HELP
+ user: isPersonal ? SMTP_USER : SMTP_USER_NOTIFY,
+ pass: isPersonal ? SMTP_PASSWORD : SMTP_PASSWORD_NOTIFY
}
});
@@ -60,14 +49,22 @@ export const sendEmail = async ({
isPersonalEmail?: boolean;
replyTo?: string;
}) => {
- await getTransporter(isPersonalEmail);
- const info = await transporter.sendMail({
- from: from || '"Best from ClassroomIO" ', // sender address
- to, // list of receivers
- subject, // Subject line
- replyTo,
- html: withEmailTemplate(content) // html body
- });
+ try {
+ await getTransporter(isPersonalEmail);
+ const info = await transporter.sendMail({
+ from: from || '"Best from ClassroomIO" ', // sender address
+ to, // list of receivers
+ subject, // Subject line
+ replyTo,
+ html: withEmailTemplate(content) // html body
+ });
- console.log('Message sent: %s', info.messageId);
+ console.log('Message sent: %s', info.messageId);
+
+ return info;
+ } catch (error) {
+ console.error({ error });
+
+ return error;
+ }
};
diff --git a/apps/dashboard/src/lib/utils/types/feed.ts b/apps/dashboard/src/lib/utils/types/feed.ts
new file mode 100644
index 00000000..39274d2f
--- /dev/null
+++ b/apps/dashboard/src/lib/utils/types/feed.ts
@@ -0,0 +1,46 @@
+export interface Author {
+ id: string;
+ username: string;
+ fullname: string;
+ avatar_url: string;
+}
+
+export interface Comment {
+ id: string;
+ created_at: string;
+ content: string;
+ author: {
+ profile: Author;
+ };
+}
+
+export interface Reaction {
+ smile: string[];
+ thumbsup: string[];
+ thumbsdown: string[];
+ clap: string[];
+}
+
+export interface FeedApi {
+ id: string;
+ content: string;
+ author: {
+ profile: Author;
+ };
+ created_at: string;
+ comment: Comment[];
+ reaction: Reaction[];
+ is_pinned: false;
+}
+
+export interface Feed {
+ id: string;
+ content: string;
+ author: {
+ profile: Author;
+ };
+ created_at: string;
+ comment: Comment[];
+ reaction: Reaction[];
+ isPinned: boolean;
+}
diff --git a/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js b/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js
index 2fe277d2..4b0ae942 100644
--- a/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/exercise_submission_update/+server.js
@@ -24,12 +24,12 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
- from: `"${orgName} (via ClassroomIO.com)" `,
+ sendEmail({
+ from: `"${orgName} (via ClassroomIO.com)" `,
to,
subject: `[Submitted]: ${exerciseTitle}`,
content
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts b/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts
new file mode 100644
index 00000000..1eee64aa
--- /dev/null
+++ b/apps/dashboard/src/routes/api/email/course/newsfeed/+server.ts
@@ -0,0 +1,85 @@
+import { json } from '@sveltejs/kit';
+import { getSupabase } from '$lib/utils/functions/supabase';
+import { sendEmail } from '$lib/utils/services/notification/send';
+import { getFeedForNotification } from '$lib/utils/services/newsfeed/index';
+
+const supabase = getSupabase();
+
+const sendEmailNotification = async (feedId: string, authorId: string, comment?: string) => {
+ const feed = await getFeedForNotification(feedId, authorId);
+
+ if (!feed) return;
+
+ const postLink = `https://${feed.org.siteName}.classroomio.com/courses/${feed.courseId}?feedId=${feed.id}`;
+
+ if (comment) {
+ // send only to teacher
+ sendEmail({
+ from: `"${feed.org.name} - ClassroomIO" `,
+ to: feed.teacherEmail,
+ subject: `[${feed.courseTitle}] - News feed comment`,
+ content: `
+ A student left you a comment on your newsfeed post
+
+ ${comment}
+
+ `
+ }).then((info) => console.log('Email sent:', info));
+
+ // dont continue
+ return;
+ }
+
+ // else send to everyone except the author of the post
+ Promise.all(
+ feed.courseMembers.map((member) => {
+ return sendEmail({
+ from: `"${feed.org.name} - ClassroomIO" `,
+ to: member.email,
+ replyTo: feed.teacherEmail,
+ subject: `[${feed.courseTitle}] - New post in course`,
+ content: `
+ ${feed.teacherName} made a post in a course you are taking: ${feed.courseTitle}.
+
+ ${feed.content}
+
+ `
+ });
+ })
+ ).then((emails) => console.log(`Sent emails to ${emails.length} students`));
+};
+
+export async function POST({ request }) {
+ const { authorId, feedId, comment } = await request.json();
+ const accessToken = request.headers.get('Authorization') || '';
+ console.log('/POST api/email/course/newsfeed');
+
+ if (!authorId || !feedId || !accessToken) {
+ 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 });
+ }
+
+ sendEmailNotification(feedId, authorId, comment);
+ // TODO: Support sending to other platforms like telegram and discord
+ // sendDiscordNotification(); sendTelegramNotification();
+
+ return json({
+ success: true,
+ message: 'Email sent'
+ });
+}
diff --git a/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js b/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js
index fabce8a6..059bb0b1 100644
--- a/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/student_prove_payment/+server.js
@@ -32,8 +32,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
- from: `"${orgName} - ClassroomIO" `,
+ sendEmail({
+ from: `"${orgName} - ClassroomIO" `,
to,
replyTo: teacherEmail,
subject: `[${courseName}] One more step left`,
@@ -44,7 +44,7 @@ export async function POST({ request }) {
Talk to you soon and see you in class.
${orgName}
`
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js b/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js
index f5a5fd6e..82fa9f01 100644
--- a/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/student_welcome/+server.js
@@ -26,8 +26,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
- from: `"${orgName} (via ClassroomIO.com)" `,
+ sendEmail({
+ from: `"${orgName} (via ClassroomIO.com)" `,
to,
subject: `${orgName} - Welcome to Class π`,
content: `
@@ -38,7 +38,7 @@ export async function POST({ request }) {
Cheers,
${orgName}
`
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/course/submission_update/+server.js b/apps/dashboard/src/routes/api/email/course/submission_update/+server.js
index b6e40408..914f2eb4 100644
--- a/apps/dashboard/src/routes/api/email/course/submission_update/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/submission_update/+server.js
@@ -24,12 +24,12 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
- from: `"${orgName} (via ClassroomIO.com)" `,
+ sendEmail({
+ from: `"${orgName} (via ClassroomIO.com)" `,
to,
subject: 'Submission Update',
content
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js b/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js
index 4fbde1a4..c9c0ea09 100644
--- a/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/teacher_student_buycourse/+server.js
@@ -31,8 +31,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
- from: `ClassroomIO" `,
+ sendEmail({
+ from: `ClassroomIO" `,
to,
subject: `[${courseName}] Request to Join Course!`,
content: `
@@ -44,7 +44,7 @@ export async function POST({ request }) {
Email: ${studentEmail}
`
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js b/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js
index 1a790758..277a10e3 100644
--- a/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/teacher_student_joined/+server.js
@@ -25,8 +25,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
- from: `"ClassroomIO" `,
+ sendEmail({
+ from: `"ClassroomIO" `,
to,
subject: `[${courseName}] You've got a new student π!`,
content: `
@@ -36,7 +36,7 @@ export async function POST({ request }) {
If you run into any issues, please donβt fail to reach out to us, weβd love to make your teaching
experience as easy as possible.
`
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js b/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js
index 9d0e73a2..1de7b6a4 100644
--- a/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js
+++ b/apps/dashboard/src/routes/api/email/course/teacher_welcome/+server.js
@@ -28,8 +28,8 @@ export async function POST({ request }) {
const origin = request.headers.get('origin');
const inviteLink = `${origin}/org/${orgSiteName}/courses`;
- await sendEmail({
- from: `"${orgName} (via ClassroomIO.com)" `,
+ sendEmail({
+ from: `"${orgName} (via ClassroomIO.com)" `,
to,
subject: `You have been invited to a course in ${orgName}!`,
content: `
@@ -40,7 +40,7 @@ export async function POST({ request }) {
Open Dashboard
`
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/invite/+server.js b/apps/dashboard/src/routes/api/email/invite/+server.js
index d60d156c..6f73f436 100644
--- a/apps/dashboard/src/routes/api/email/invite/+server.js
+++ b/apps/dashboard/src/routes/api/email/invite/+server.js
@@ -12,7 +12,7 @@ export async function POST({ request }) {
const accessToken = request.headers.get('Authorization');
console.log('/POST api/email/invite', body);
- if (!org || !Object.keys(org).length || !email) {
+ if (!org || !Object.keys(org).length || !email || !accessToken) {
return json(
{ success: false, message: 'Org data and Teacher name are required' },
{ status: 400 }
@@ -42,7 +42,7 @@ export async function POST({ request }) {
const inviteLink = `${origin}/invite/t/${encodeURIComponent(btoa(inviteData))}`;
console.log('inviteData', inviteData);
- await sendEmail({
+ sendEmail({
to: email,
subject: `Join ${name} on ClassroomIO π`,
content: `
@@ -53,7 +53,7 @@ export async function POST({ request }) {
`,
isPersonalEmail: true
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/api/email/welcome/+server.js b/apps/dashboard/src/routes/api/email/welcome/+server.js
index 842e103d..64b93ee2 100644
--- a/apps/dashboard/src/routes/api/email/welcome/+server.js
+++ b/apps/dashboard/src/routes/api/email/welcome/+server.js
@@ -9,7 +9,7 @@ export async function POST({ request }) {
const accessToken = request.headers.get('Authorization');
console.log('/POST api/email/welcome', to, name);
- if (!to || !name) {
+ if (!to || !name || !accessToken) {
return json({ success: false, message: 'Name and To are required fields' }, { status: 400 });
}
@@ -25,7 +25,7 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
- await sendEmail({
+ sendEmail({
to,
subject: 'Thank you so so so much for choosing ClassroomIO!',
content: `
@@ -48,7 +48,7 @@ export async function POST({ request }) {
`,
isPersonalEmail: true
- });
+ }).then((info) => console.log('Email sent:', info));
return json({
success: true,
diff --git a/apps/dashboard/src/routes/courses/[id]/+page.svelte b/apps/dashboard/src/routes/courses/[id]/+page.svelte
index 372580ed..e1451bdb 100644
--- a/apps/dashboard/src/routes/courses/[id]/+page.svelte
+++ b/apps/dashboard/src/routes/courses/[id]/+page.svelte
@@ -1,10 +1,279 @@
-