From 3e48cd650f3827248fd53a81fc1dc17f491b26cb Mon Sep 17 00:00:00 2001 From: NiallJoeMaher Date: Mon, 26 Feb 2024 14:24:04 +0000 Subject: [PATCH 1/5] Add newsletter subscription feature --- app/(app)/settings/page.tsx | 19 +++++++++++-- server/api/router/profile.ts | 18 +++++++++++-- server/lib/newsletter.ts | 52 ++++++++++++++++++++++++++++-------- 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/app/(app)/settings/page.tsx b/app/(app)/settings/page.tsx index f4566d1d..593999b2 100644 --- a/app/(app)/settings/page.tsx +++ b/app/(app)/settings/page.tsx @@ -1,8 +1,9 @@ -import { redirect } from "next/navigation"; +import { notFound, redirect } from "next/navigation"; import Content from "./_client"; import { getServerAuthSession } from "@/server/auth"; import { customAlphabet } from "nanoid"; import prisma from "@/server/db/client"; +import { isUserSubscribedToNewsletter } from "@/server/lib/newsletter"; export const metadata = { title: "Settings - Update your profile", @@ -55,5 +56,19 @@ export default async function Page() { return ; } - return ; + if (!session.user.email) { + return notFound(); + } + + try { + const newsletter = await isUserSubscribedToNewsletter(session.user.email); + console.log("newsletter", newsletter); + const cleanedUser = { + ...user, + newsletter, + }; + return ; + } catch (error) { + return ; + } } diff --git a/server/api/router/profile.ts b/server/api/router/profile.ts index ea54f08a..e41636ad 100644 --- a/server/api/router/profile.ts +++ b/server/api/router/profile.ts @@ -8,7 +8,10 @@ import { import { getPresignedUrl } from "../../common/getPresignedUrl"; import { createTRPCRouter, publicProcedure, protectedProcedure } from "../trpc"; -import { manageNewsletterSubscription } from "@/server/lib/newsletter"; +import { + isUserSubscribedToNewsletter, + manageNewsletterSubscription, +} from "@/server/lib/newsletter"; import { TRPCError } from "@trpc/server"; import { nanoid } from "nanoid"; @@ -22,7 +25,18 @@ export const profileRouter = createTRPCRouter({ }, }); - if (existingProfile?.newsletter !== input.newsletter) { + const { email } = ctx.session.user; + + if (!email) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Email not found", + }); + } + + const newsletter = await isUserSubscribedToNewsletter(email); + + if (newsletter !== input.newsletter) { const email = existingProfile?.email; const action = input.newsletter ? "subscribe" : "unsubscribe"; if (!email) { diff --git a/server/lib/newsletter.ts b/server/lib/newsletter.ts index 9e3d14b3..9fdfe156 100644 --- a/server/lib/newsletter.ts +++ b/server/lib/newsletter.ts @@ -20,21 +20,51 @@ export async function manageNewsletterSubscription( silent: "true", // Don't send a confirmation email (using this option for users signed up to platform, not newsletter only option) }).toString(); - try { - const response = await fetch(`${EMAIL_API_ENDPOINT}/${action}`, { + const response = await fetch(`${EMAIL_API_ENDPOINT}/${action}`, { + method: "POST", + headers: { + "Content-type": "application/x-www-form-urlencoded", + }, + body: payload, + }); + + if (response.ok) { + return { message: `Successfully ${action}d to the newsletter.` }; + } else { + throw new Error(`Failed to ${action} to the newsletter`); + } +} + +export async function isUserSubscribedToNewsletter(email: string) { + const EMAIL_API_ENDPOINT = process.env.EMAIL_API_ENDPOINT; + const EMAIL_API_KEY = process.env.EMAIL_API_KEY; + const EMAIL_NEWSLETTER_ID = process.env.EMAIL_NEWSLETTER_ID; + + if (!EMAIL_API_ENDPOINT || !EMAIL_API_KEY || !EMAIL_NEWSLETTER_ID) { + throw new Error("Email API not configured"); + } + + const payload = new URLSearchParams({ + email, + api_key: EMAIL_API_KEY, + list_id: EMAIL_NEWSLETTER_ID, + }).toString(); + + const response = await fetch( + `${EMAIL_API_ENDPOINT}/api/subscribers/subscription-status.php`, + { method: "POST", headers: { "Content-type": "application/x-www-form-urlencoded", }, body: payload, - }); - - if (response.ok) { - return { message: `Successfully ${action}d to the newsletter.` }; - } else { - throw new Error(`Failed to ${action} to the newsletter`); - } - } catch (error) { - Sentry.captureException(error); + }, + ); + + if (response.ok) { + const status = await response.text(); + return status === "Subscribed"; + } else { + throw new Error("Failed to check newsletter subscription"); } } From 6726a5cc97a1992b59b4b7224827edf6da64e100 Mon Sep 17 00:00:00 2001 From: NiallJoeMaher Date: Mon, 26 Feb 2024 14:24:18 +0000 Subject: [PATCH 2/5] Add playwright install command to test script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b6979224..805b5faf 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lint:fix": "next lint --fix", "prettier": "prettier --check -c '**/*.{ts,tsx,js,jsx,json,json5,scss,css,html,mdx}'", "prettier:fix": "prettier --write -c '**/*.{ts,tsx,js,jsx,json,json5,scss,css,html,mdx}'", - "test": "playwright test", + "test": "npx playwright install && playwright test", "studio": "prisma studio", "migrate": "npx prisma migrate", "prepare": "husky install" From 67d4ada63f1b8764954a4ce085c5fc72dc3ebb31 Mon Sep 17 00:00:00 2001 From: NiallJoeMaher Date: Mon, 26 Feb 2024 14:28:53 +0000 Subject: [PATCH 3/5] Remove unused log --- app/(app)/settings/page.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/(app)/settings/page.tsx b/app/(app)/settings/page.tsx index 593999b2..2f7f66ee 100644 --- a/app/(app)/settings/page.tsx +++ b/app/(app)/settings/page.tsx @@ -62,7 +62,6 @@ export default async function Page() { try { const newsletter = await isUserSubscribedToNewsletter(session.user.email); - console.log("newsletter", newsletter); const cleanedUser = { ...user, newsletter, From 2008ce28c59636bb4bef31b5b81a2df4b7326dd3 Mon Sep 17 00:00:00 2001 From: Niall Maher Date: Mon, 26 Feb 2024 14:32:34 +0000 Subject: [PATCH 4/5] Update app/(app)/settings/page.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- app/(app)/settings/page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/app/(app)/settings/page.tsx b/app/(app)/settings/page.tsx index 2f7f66ee..99f34a31 100644 --- a/app/(app)/settings/page.tsx +++ b/app/(app)/settings/page.tsx @@ -68,6 +68,7 @@ export default async function Page() { }; return ; } catch (error) { + Sentry.captureException(error); return ; } } From 35af93896f5f3edd71a6f74111bd4b590056019c Mon Sep 17 00:00:00 2001 From: NiallJoeMaher Date: Mon, 26 Feb 2024 14:36:18 +0000 Subject: [PATCH 5/5] Cleanup unused code and import Sentry --- app/(app)/settings/page.tsx | 1 + server/api/router/profile.ts | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/app/(app)/settings/page.tsx b/app/(app)/settings/page.tsx index 99f34a31..a43dafb9 100644 --- a/app/(app)/settings/page.tsx +++ b/app/(app)/settings/page.tsx @@ -3,6 +3,7 @@ import Content from "./_client"; import { getServerAuthSession } from "@/server/auth"; import { customAlphabet } from "nanoid"; import prisma from "@/server/db/client"; +import * as Sentry from "@sentry/nextjs"; import { isUserSubscribedToNewsletter } from "@/server/lib/newsletter"; export const metadata = { diff --git a/server/api/router/profile.ts b/server/api/router/profile.ts index e41636ad..79ddb2a4 100644 --- a/server/api/router/profile.ts +++ b/server/api/router/profile.ts @@ -19,12 +19,6 @@ export const profileRouter = createTRPCRouter({ edit: protectedProcedure .input(saveSettingsSchema) .mutation(async ({ input, ctx }) => { - const existingProfile = await ctx.db.user.findUnique({ - where: { - id: ctx.session.user.id, - }, - }); - const { email } = ctx.session.user; if (!email) { @@ -37,7 +31,6 @@ export const profileRouter = createTRPCRouter({ const newsletter = await isUserSubscribedToNewsletter(email); if (newsletter !== input.newsletter) { - const email = existingProfile?.email; const action = input.newsletter ? "subscribe" : "unsubscribe"; if (!email) { throw new TRPCError({