diff --git a/apps/web/src/app/(dashboard)/admin/waitlist/page.tsx b/apps/web/src/app/(dashboard)/admin/waitlist/page.tsx index 9bc859c..a18fcc7 100644 --- a/apps/web/src/app/(dashboard)/admin/waitlist/page.tsx +++ b/apps/web/src/app/(dashboard)/admin/waitlist/page.tsx @@ -78,6 +78,15 @@ export default function AdminWaitlistPage() { }, }); + const rejectWaitlist = api.admin.rejectWaitlistUser.useMutation({ + onSuccess: () => { + toast.success("Rejection email sent"); + }, + onError: (error) => { + toast.error(error.message ?? "Unable to send rejection email"); + }, + }); + const onSubmit = (values: SearchInput) => { setHasSearched(false); setUserResult(null); @@ -89,6 +98,11 @@ export default function AdminWaitlistPage() { updateWaitlist.mutate({ userId: userResult.id, isWaitlisted: checked }); }; + const handleReject = () => { + if (!userResult) return; + rejectWaitlist.mutate({ userId: userResult.id }); + }; + if (!isCloud()) { return (
@@ -166,22 +180,47 @@ export default function AdminWaitlistPage() {
-
-
-

Waitlist access

-

- Toggle to control whether the user remains on the waitlist. -

+
+
+
+

Waitlist access

+

+ Toggle to control whether the user remains on the waitlist. +

+
+
+ + {updateWaitlist.isPending ? ( + + ) : null} +
-
- - {updateWaitlist.isPending ? ( - - ) : null} + +
+
+

Reject waitlist request

+

+ Send the applicant a rejection email without changing their waitlist status. +

+
+
diff --git a/apps/web/src/server/api/routers/admin.ts b/apps/web/src/server/api/routers/admin.ts index fe2c8dc..a58c45e 100644 --- a/apps/web/src/server/api/routers/admin.ts +++ b/apps/web/src/server/api/routers/admin.ts @@ -214,6 +214,67 @@ export const adminRouter = createTRPCRouter({ return updatedUser; }), + rejectWaitlistUser: adminProcedure + .input( + z.object({ + userId: z.number(), + }) + ) + .mutation(async ({ input }) => { + const user = await db.user.findUnique({ + where: { id: input.userId }, + select: waitlistUserSelection, + }); + + if (!user) { + throw new Error("User not found"); + } + + if (!user.email) { + throw new Error("User email is missing"); + } + + const founderEmail = env.FOUNDER_EMAIL ?? undefined; + const fallbackFrom = env.FROM_EMAIL ?? env.ADMIN_EMAIL ?? undefined; + + const replyTo = founderEmail ?? fallbackFrom; + + if (!replyTo) { + throw new Error("No sender email configured"); + } + + const fromOverride = founderEmail ?? undefined; + + const text = [ + "Hello,", + "", + "Sorry, We cannot proceed with this request at this time, this might affect useSend\u2019s sending reputation.", + "", + "", + "cheers,", + "koushik - useSend.com", + ].join("\n"); + + try { + await sendMail( + user.email, + "useSend: Waitlist request update", + text, + toPlainHtml(text), + replyTo, + fromOverride + ); + } catch (error) { + logger.error( + { userId: user.id, error }, + "Failed to send waitlist rejection email" + ); + throw new Error("Failed to send waitlist rejection email"); + } + + return { sent: true }; + }), + findTeam: adminProcedure .input( z.object({