payload-plugin-newsletter 0.13.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1261,6 +1261,44 @@ var createNewsletterSettingsGlobal = (pluginConfig) => {
1261
1261
  }
1262
1262
  ]
1263
1263
  },
1264
+ {
1265
+ label: "Brand Settings",
1266
+ fields: [
1267
+ {
1268
+ name: "brandSettings",
1269
+ type: "group",
1270
+ label: "Brand Settings",
1271
+ fields: [
1272
+ {
1273
+ name: "siteName",
1274
+ type: "text",
1275
+ label: "Site Name",
1276
+ required: true,
1277
+ defaultValue: "Newsletter",
1278
+ admin: {
1279
+ description: "Your website or newsletter name"
1280
+ }
1281
+ },
1282
+ {
1283
+ name: "siteUrl",
1284
+ type: "text",
1285
+ label: "Site URL",
1286
+ admin: {
1287
+ description: "Your website URL (optional)"
1288
+ }
1289
+ },
1290
+ {
1291
+ name: "logoUrl",
1292
+ type: "text",
1293
+ label: "Logo URL",
1294
+ admin: {
1295
+ description: "URL to your logo image (optional)"
1296
+ }
1297
+ }
1298
+ ]
1299
+ }
1300
+ ]
1301
+ },
1264
1302
  {
1265
1303
  label: "Email Templates",
1266
1304
  fields: [
@@ -1944,10 +1982,13 @@ function verifySessionToken(token) {
1944
1982
  throw error;
1945
1983
  }
1946
1984
  }
1947
- function generateMagicLinkURL(token, baseURL, config) {
1985
+ function generateMagicLinkURL(token, baseURL, config, redirectUrl) {
1948
1986
  const path = config.auth?.magicLinkPath || "/newsletter/verify";
1949
1987
  const url = new URL(path, baseURL);
1950
1988
  url.searchParams.set("token", token);
1989
+ if (redirectUrl) {
1990
+ url.searchParams.set("redirect", redirectUrl);
1991
+ }
1951
1992
  return url.toString();
1952
1993
  }
1953
1994
 
@@ -2001,20 +2042,93 @@ var createSubscribeEndpoint = (config) => {
2001
2042
  if (existing.docs.length > 0) {
2002
2043
  const subscriber2 = existing.docs[0];
2003
2044
  if (subscriber2.subscriptionStatus === "unsubscribed") {
2045
+ const allowResubscribe = config.auth?.allowResubscribe ?? false;
2046
+ if (!allowResubscribe) {
2047
+ return Response.json({
2048
+ success: false,
2049
+ error: "This email has been unsubscribed. Please contact support to resubscribe."
2050
+ }, { status: 400 });
2051
+ }
2052
+ const updated = await req.payload.update({
2053
+ collection: config.subscribersSlug || "subscribers",
2054
+ id: subscriber2.id,
2055
+ data: {
2056
+ subscriptionStatus: "active",
2057
+ resubscribedAt: (/* @__PURE__ */ new Date()).toISOString(),
2058
+ // Preserve preferences but update metadata
2059
+ signupMetadata: {
2060
+ ...metadata,
2061
+ source: source || "resubscribe",
2062
+ resubscribedFrom: subscriber2.signupMetadata?.source
2063
+ }
2064
+ },
2065
+ overrideAccess: true
2066
+ });
2067
+ if (config.hooks?.afterSubscribe) {
2068
+ await config.hooks.afterSubscribe({
2069
+ doc: updated,
2070
+ req
2071
+ });
2072
+ }
2073
+ const emailService = req.payload.newsletterEmailService;
2074
+ if (emailService) {
2075
+ const settings2 = await req.payload.findGlobal({
2076
+ slug: config.settingsSlug || "newsletter-settings"
2077
+ });
2078
+ const html = await renderEmail("welcome", {
2079
+ name: updated.name || "",
2080
+ email: updated.email,
2081
+ siteName: settings2?.brandSettings?.siteName || "Newsletter",
2082
+ siteUrl: req.payload.config.serverURL || ""
2083
+ });
2084
+ await emailService.send({
2085
+ to: updated.email,
2086
+ subject: `Welcome back to ${settings2?.brandSettings?.siteName || "our newsletter"}!`,
2087
+ html
2088
+ });
2089
+ }
2004
2090
  return Response.json({
2005
- success: false,
2006
- error: "This email has been unsubscribed. Please contact support to resubscribe."
2007
- }, { status: 400 });
2091
+ success: true,
2092
+ message: "Welcome back! You have been resubscribed.",
2093
+ subscriber: {
2094
+ id: updated.id,
2095
+ email: updated.email,
2096
+ subscriptionStatus: updated.subscriptionStatus
2097
+ },
2098
+ wasResubscribed: true
2099
+ });
2008
2100
  }
2009
- return Response.json({
2010
- success: false,
2011
- error: "Already subscribed",
2012
- subscriber: {
2013
- id: subscriber2.id,
2014
- email: subscriber2.email,
2015
- subscriptionStatus: subscriber2.subscriptionStatus
2101
+ if (subscriber2.subscriptionStatus === "active") {
2102
+ const token = generateMagicLinkToken(
2103
+ String(subscriber2.id),
2104
+ subscriber2.email,
2105
+ config
2106
+ );
2107
+ const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || "";
2108
+ const magicLinkURL = generateMagicLinkURL(token, serverURL, config);
2109
+ const emailService = req.payload.newsletterEmailService;
2110
+ if (emailService) {
2111
+ const settings2 = await req.payload.findGlobal({
2112
+ slug: config.settingsSlug || "newsletter-settings"
2113
+ });
2114
+ const html = await renderEmail("signin", {
2115
+ magicLink: magicLinkURL,
2116
+ email: subscriber2.email,
2117
+ siteName: settings2?.brandSettings?.siteName || "Newsletter",
2118
+ expiresIn: config.auth?.tokenExpiration || "7d"
2119
+ });
2120
+ await emailService.send({
2121
+ to: subscriber2.email,
2122
+ subject: `Sign in to ${settings2?.brandSettings?.siteName || "your account"}`,
2123
+ html
2124
+ });
2016
2125
  }
2017
- }, { status: 400 });
2126
+ return Response.json({
2127
+ success: true,
2128
+ message: "You are already subscribed! Check your email for a sign-in link.",
2129
+ alreadySubscribed: true
2130
+ });
2131
+ }
2018
2132
  }
2019
2133
  const ipAddress = req.ip || req.connection?.remoteAddress;
2020
2134
  const maxPerIP = settings?.subscriptionSettings?.maxSubscribersPerIP || 10;
@@ -2536,7 +2650,7 @@ var createSigninEndpoint = (config) => {
2536
2650
  handler: async (req) => {
2537
2651
  try {
2538
2652
  const data = await req.json();
2539
- const { email } = data;
2653
+ const { email, redirectUrl } = data;
2540
2654
  const validation = validateSubscriberData({ email });
2541
2655
  if (!validation.valid) {
2542
2656
  return Response.json({
@@ -2555,8 +2669,7 @@ var createSigninEndpoint = (config) => {
2555
2669
  const result = await req.payload.find({
2556
2670
  collection: config.subscribersSlug || "subscribers",
2557
2671
  where: {
2558
- email: { equals: email.toLowerCase() },
2559
- subscriptionStatus: { equals: "active" }
2672
+ email: { equals: email.toLowerCase() }
2560
2673
  },
2561
2674
  limit: 1,
2562
2675
  overrideAccess: true
@@ -2565,17 +2678,31 @@ var createSigninEndpoint = (config) => {
2565
2678
  if (result.docs.length === 0) {
2566
2679
  return Response.json({
2567
2680
  success: false,
2568
- error: "Email not found. Please subscribe first."
2681
+ error: "Email not found. Please subscribe first.",
2682
+ requiresSubscribe: true
2569
2683
  }, { status: 404 });
2570
2684
  }
2571
2685
  const subscriber = result.docs[0];
2686
+ const allowUnsubscribed = config.auth?.allowUnsubscribedSignin ?? false;
2687
+ if (subscriber.subscriptionStatus === "unsubscribed" && !allowUnsubscribed) {
2688
+ return Response.json({
2689
+ success: false,
2690
+ error: "Your subscription is inactive. Please resubscribe to sign in.",
2691
+ subscriber: {
2692
+ id: subscriber.id,
2693
+ email: subscriber.email,
2694
+ subscriptionStatus: subscriber.subscriptionStatus
2695
+ },
2696
+ requiresResubscribe: true
2697
+ }, { status: 403 });
2698
+ }
2572
2699
  const token = generateMagicLinkToken(
2573
2700
  String(subscriber.id),
2574
2701
  subscriber.email,
2575
2702
  config
2576
2703
  );
2577
2704
  const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || "";
2578
- const magicLinkURL = generateMagicLinkURL(token, serverURL, config);
2705
+ const magicLinkURL = generateMagicLinkURL(token, serverURL, config, redirectUrl);
2579
2706
  const emailService = req.payload.newsletterEmailService;
2580
2707
  if (emailService) {
2581
2708
  const settings = await req.payload.findGlobal({