Skip to content

Feat announcement discussion notifier#53

Open
TrickkyRicky wants to merge 11 commits into
mainfrom
feat-announcement-discussion-notifier
Open

Feat announcement discussion notifier#53
TrickkyRicky wants to merge 11 commits into
mainfrom
feat-announcement-discussion-notifier

Conversation

@TrickkyRicky

@TrickkyRicky TrickkyRicky commented Apr 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds automated email notifications whenever a new announcement or discussion thread is created, so platform members are immediately informed without having to check the app manually.


Email Notifications

New email templates

  • src/emails/AnnouncementNotification.tsx - email template for new announcements
  • src/emails/NewThreadNotification.tsx - email template for new discussion threads

New API routes

  • src/app/api/announcement-emails/route.ts - POST endpoint that looks up an announcement by ID, queries users filtered by the announcement's groupType (ALL, NONPROFIT, SUPPLIER, ADMIN), and sends a batch email via Resend
  • src/app/api/discussion-emails/route.ts - same pattern for discussion threads

Trigger integration

  • src/app/announcements/announcements-grid.tsx - fires POST /api/announcement-emails after a new announcement is created
  • src/app/discussion/discussion-grid.tsx - fires POST /api/discussion-emails after a new thread is created; both calls are fire-and-forget

Images


discussionProof AnnouncementProof image

@TrickkyRicky TrickkyRicky requested a review from a team as a code owner April 13, 2026 04:40

@Wesley-Baker Wesley-Baker left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me.

@TrickkyRicky TrickkyRicky requested a review from mrysav April 19, 2026 00:49

@whao37 whao37 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There might be some little bugs I've missed but these are the big ones I've seen. Please double check though since I might've missed reference files.

Comment on lines +9 to +48
export async function POST(req: Request) {
try {
const session = await auth();
if (!session || !session.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

const { announcementId } = await req.json();

if (!announcementId) {
return NextResponse.json(
{ error: 'Announcement ID is required' },
{ status: 400 }
);
}

const announcement = await prisma.announcement.findUnique({
where: { id: announcementId },
include: {
author: { select: { name: true } },
},
});

if (!announcement) {
return NextResponse.json(
{ error: 'Announcement not found' },
{ status: 404 }
);
}

// Build role filter based on groupType; exclude users who opted out of emails
const roleFilter =
announcement.groupType === GroupType.ALL
? {}
: { role: announcement.groupType as unknown as UserRole };

const users = await prisma.user.findMany({
where: { ...roleFilter, announcementEmailOptOut: false },
select: { email: true, name: true },
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe any authenticated user can POST with an announcementId or threadId can trigger resent to every user who aren't opted out. I'm not sure if there is an admin/staff check already here but this could cause abuse from bad actors.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/api/announcement-emails: now requires role === ADMIN; any other authenticated user gets a 401.
/api/discussion-emails: now verifies the caller is the thread's author thread.author.id === session.user.id; mismatched callers get a 401.

Comment on lines +9 to +43
export async function POST(req: Request) {
try {
const session = await auth();
if (!session || !session.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

const { threadId } = await req.json();

if (!threadId) {
return NextResponse.json(
{ error: 'Thread ID is required' },
{ status: 400 }
);
}

const thread = await prisma.thread.findUnique({
where: { id: threadId },
include: {
author: { select: { name: true } },
},
});

if (!thread) {
return NextResponse.json({ error: 'Thread not found' }, { status: 404 });
}

// Build role filter based on groupType; exclude users who opted out of emails
const roleFilter =
thread.groupType === GroupType.ALL ? {} : { role: thread.groupType };

const users = await prisma.user.findMany({
where: { ...roleFilter, discussionEmailOptOut: false },
select: { email: true, name: true },
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same pattern for threadId.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as abaove

Comment thread src/app/announcements/announcements-grid.tsx
Comment thread src/app/settings/email-settings-form.tsx Outdated
@TrickkyRicky TrickkyRicky requested a review from whao37 April 20, 2026 17:32

@whao37 whao37 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixes look good to me

@mrysav

mrysav commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

@TrickkyRicky To reiterate something we talked about synchronously: I think this PR looks good, but I know there's a bit more testing you want to do. Happy to approve and merge when you are ready.

@TrickkyRicky TrickkyRicky force-pushed the feat-announcement-discussion-notifier branch from f1982d5 to 277003c Compare June 7, 2026 00:07
@TrickkyRicky

TrickkyRicky commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

@TrickkyRicky To reiterate something we talked about synchronously: I think this PR looks good, but I know there's a bit more testing you want to do. Happy to approve and merge when you are ready.

Hello I am finished testing, I used 4 of my personal emails and Chrome + Safari + incognito for each browser as well to get 4 separate logins lol, but everything looks good.

One potential issue I found was that if an email had a redirect such as abcdef+foo@gmail.com that +foo would send the email to spam sometimes.

  • Discussion and Announcement targeted role groups
  • Email Opt-Out (Unsubscribe)
  • Supplier Claimed Product Email
  • Supplier Partially Claimed Product Email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants