student quiz notifications and Resend email notifications#51
student quiz notifications and Resend email notifications#51FlashKnight3 wants to merge 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds student-facing quiz assignment notifications and introduces Resend email notifications when a quiz is assigned.
Changes:
- Add
app/api/student/notificationsGET/PATCH endpoints to fetch and mark quiz-assigned notifications as read. - When assigning a quiz, insert a
Notificationsrow for the student. - When assigning a quiz, send an email via Resend to the student (if they have an email).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| app/api/student/notifications/route.ts | New student notifications API (list + mark read) for quiz_assigned events. |
| app/api/quiz/assign/route.ts | Creates in-app notifications and sends Resend emails on quiz assignment. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { NextRequest, NextResponse } from "next/server"; | ||
| import { createClient } from "@supabase/supabase-js"; | ||
| import {Resend} from "resend"; |
There was a problem hiding this comment.
The new resend import will fail at runtime/build because the resend package isn’t present in package.json/package-lock.json. Add it as a dependency (and lockfile update) so this route can compile in CI.
| // Notify student that a quiz has been assigned | ||
| await supabase.from("Notifications").insert({ | ||
| student_id: studentId, | ||
| educator_id: educatorId, | ||
| quiz_id: newQuiz.id, | ||
| type: "quiz_assigned", | ||
| is_read: false, | ||
| }); |
There was a problem hiding this comment.
The Notifications insert result is ignored. If this insert fails, the API still returns success and the student won’t see an in-app notification; please capture error and handle it (return 500 or at least log/report it).
| //Send email notification (Resend) | ||
| const { data: studentData } = await supabase | ||
| .from("Students") | ||
| .select("email, first_name") | ||
| .eq("id", studentId) | ||
| .single(); | ||
|
|
||
| if (studentData?.email) { | ||
| const resend = new Resend(process.env.RESEND_API_KEY); | ||
| await resend.emails.send({ | ||
| from: "8 Million Stories <onboarding@resend.dev>", //must change later to actual domain | ||
| to: studentData.email, | ||
| subject: "You have a new quiz assigned", | ||
| html: ` | ||
| <p>Hi ${studentData.first_name ?? "there"},</p> | ||
| <p>Your instructor has assigned you a new quiz: <strong>${sourceQuiz.name?.trim() || "Quiz"}</strong>.</p> | ||
| <p>Log in to your dashboard to get started.</p> | ||
| `, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Email sending is inside the main try and not isolated. If Resend throws (missing/invalid RESEND_API_KEY, network issues, etc.), the handler returns 500 even though the quiz (and possibly deadline/notification) has already been created, which can cause clients to retry and create duplicate assignments. Consider making email best-effort (wrap in its own try/catch + log) or send asynchronously after the assignment is successfully returned.
| function getAdminClient() { | ||
| const url = process.env.NEXT_PUBLIC_SUPABASE_URL; | ||
| const key = process.env.SUPABASE_SERVICE_ROLE_KEY; | ||
| if (!url || !key) return null; | ||
| return createServiceClient(url, key); | ||
| } |
There was a problem hiding this comment.
getAdminClient() is duplicated from app/api/educator/notifications/route.ts (same env var checks + service client creation). Consider extracting a shared helper (e.g. in lib/supabase/admin.ts) to avoid drift across routes that need the service-role client.
778fc3a to
b04e436
Compare
No description provided.