feat: course news feed (#136)

* style: Improved font size of the answers in the FAQ section of the landing page

* woking on the anouncement page

* working on the anouncement feature

* fixed some bugs in the emoji and comment

* minor cleanup

* Delete .github/workflows/test-pull-request.yml

This commit was stashed but it seems i accidentally applied on this commit

* updated the navicon for the anouncement

* added role level security

* still working on the emoji click

* everything works now

* cleaned up the code

* cleaned up the code

* cleaned up the code

* cleaned up the code

* refined the formatTime function using dayjs

* refined the formatTime function using dayjs

* typed,the code,created a migration file

* increase editor width/height

* added the confirmation modal and also the edit functionality for a improve UX

* some cleanup

* handle edge case,only tutor or admin can edit or delete

* improved the fetchNews function and also added role level access for deleting the comment

* chore: refactor code

* clean up

* feat: add pinned feed

* feat: remove overview on sidebar

* fix formatting of todo

* feat: prevent async block when sending email

* feat: notify teacher and student of new post/comment

* refactoring

---------

Co-authored-by: Rotimi Best <[email protected]>
Co-authored-by: Rotimi Best <[email protected]>
This commit is contained in:
Em_Dev
2024-02-28 03:00:31 +01:00
committed by GitHub
co-authored by Rotimi Best Rotimi Best
parent 474e83c3d9
commit 5cdb74a6b5
39 changed files with 1141 additions and 275 deletions
@@ -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)" <help@classroomio.com>`,
sendEmail({
from: `"${orgName} (via ClassroomIO.com)" <notify@classroomio.com>`,
to,
subject: `[Submitted]: ${exerciseTitle}`,
content
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -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" <[email protected]>`,
to: feed.teacherEmail,
subject: `[${feed.courseTitle}] - News feed comment`,
content: `
<p>A student left you a comment on your newsfeed post</p>
<div style="font-style: italic; margin-top: 10px;">${comment}</div>
<div>
<a class="button" href="${postLink}">View comment</a>
</div>
`
}).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" <[email protected]>`,
to: member.email,
replyTo: feed.teacherEmail,
subject: `[${feed.courseTitle}] - New post in course`,
content: `
<p>${feed.teacherName} made a post in a course you are taking: ${feed.courseTitle}.</p>
<div style="font-style: italic; margin-top: 10px;">${feed.content}</div>
<div>
<a class="button" href="${postLink}">View post</a>
</div>
`
});
})
).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'
});
}
@@ -32,8 +32,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
await sendEmail({
from: `"${orgName} - ClassroomIO" <help@classroomio.com>`,
sendEmail({
from: `"${orgName} - ClassroomIO" <notify@classroomio.com>`,
to,
replyTo: teacherEmail,
subject: `[${courseName}] One more step left`,
@@ -44,7 +44,7 @@ export async function POST({ request }) {
<p>Talk to you soon and see you in class.</p>
<p>${orgName}</p>
`
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -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)" <help@classroomio.com>`,
sendEmail({
from: `"${orgName} (via ClassroomIO.com)" <notify@classroomio.com>`,
to,
subject: `${orgName} - Welcome to Class 🎉`,
content: `
@@ -38,7 +38,7 @@ export async function POST({ request }) {
<p>Cheers,</p>
<p>${orgName}</p>
`
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -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)" <help@classroomio.com>`,
sendEmail({
from: `"${orgName} (via ClassroomIO.com)" <notify@classroomio.com>`,
to,
subject: 'Submission Update',
content
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -31,8 +31,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
await sendEmail({
from: `ClassroomIO" <help@classroomio.com>`,
sendEmail({
from: `ClassroomIO" <notify@classroomio.com>`,
to,
subject: `[${courseName}] Request to Join Course!`,
content: `
@@ -44,7 +44,7 @@ export async function POST({ request }) {
Email: ${studentEmail}
</p>
`
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -25,8 +25,8 @@ export async function POST({ request }) {
return json({ success: false, message: 'Unauthenticated user' }, { status: 401 });
}
await sendEmail({
from: `"ClassroomIO" <help@classroomio.com>`,
sendEmail({
from: `"ClassroomIO" <notify@classroomio.com>`,
to,
subject: `[${courseName}] You've got a new student 🎉!`,
content: `
@@ -36,7 +36,7 @@ export async function POST({ request }) {
<p>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.</p>
`
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -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)" <help@classroomio.com>`,
sendEmail({
from: `"${orgName} (via ClassroomIO.com)" <notify@classroomio.com>`,
to,
subject: `You have been invited to a course in ${orgName}!`,
content: `
@@ -40,7 +40,7 @@ export async function POST({ request }) {
<a class="button" href="${inviteLink}">Open Dashboard</a>
</div>
`
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -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 }) {
</div>
`,
isPersonalEmail: true
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,
@@ -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 }) {
</div>
`,
isPersonalEmail: true
});
}).then((info) => console.log('Email sent:', info));
return json({
success: true,