payload-plugin-newsletter 0.7.1 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,4 +1,7 @@
1
- ## [0.7.1] - 2025-06-30
1
+ ## [0.8.0] - 2025-06-30
2
+
3
+ - feat: complete welcome email implementation in afterCreate hook
4
+
2
5
 
3
6
  ### Fixed
4
7
  - Fixed CI test runner error by adding explicit Rollup dependency for Linux platforms
package/dist/index.cjs CHANGED
@@ -101,6 +101,238 @@ var adminOrSelf = (config) => ({ req, id }) => {
101
101
  return false;
102
102
  };
103
103
 
104
+ // src/emails/render.tsx
105
+ var import_render = require("@react-email/render");
106
+
107
+ // src/emails/MagicLink.tsx
108
+ var import_components = require("@react-email/components");
109
+
110
+ // src/emails/styles.ts
111
+ var styles = {
112
+ main: {
113
+ backgroundColor: "#f6f9fc",
114
+ fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif'
115
+ },
116
+ container: {
117
+ backgroundColor: "#ffffff",
118
+ border: "1px solid #f0f0f0",
119
+ borderRadius: "5px",
120
+ margin: "0 auto",
121
+ padding: "45px",
122
+ marginBottom: "64px",
123
+ maxWidth: "500px"
124
+ },
125
+ heading: {
126
+ fontSize: "24px",
127
+ letterSpacing: "-0.5px",
128
+ lineHeight: "1.3",
129
+ fontWeight: "600",
130
+ color: "#484848",
131
+ margin: "0 0 20px",
132
+ padding: "0"
133
+ },
134
+ text: {
135
+ fontSize: "16px",
136
+ lineHeight: "26px",
137
+ fontWeight: "400",
138
+ color: "#484848",
139
+ margin: "16px 0"
140
+ },
141
+ button: {
142
+ backgroundColor: "#000000",
143
+ borderRadius: "5px",
144
+ color: "#fff",
145
+ fontSize: "16px",
146
+ fontWeight: "bold",
147
+ textDecoration: "none",
148
+ textAlign: "center",
149
+ display: "block",
150
+ width: "100%",
151
+ padding: "14px 20px",
152
+ margin: "30px 0"
153
+ },
154
+ link: {
155
+ color: "#2754C5",
156
+ fontSize: "14px",
157
+ textDecoration: "underline",
158
+ wordBreak: "break-all"
159
+ },
160
+ hr: {
161
+ borderColor: "#e6ebf1",
162
+ margin: "30px 0"
163
+ },
164
+ footer: {
165
+ fontSize: "14px",
166
+ lineHeight: "24px",
167
+ color: "#9ca2ac",
168
+ textAlign: "center",
169
+ margin: "0"
170
+ },
171
+ code: {
172
+ display: "inline-block",
173
+ padding: "16px",
174
+ width: "100%",
175
+ backgroundColor: "#f4f4f4",
176
+ borderRadius: "5px",
177
+ border: "1px solid #eee",
178
+ fontSize: "14px",
179
+ fontFamily: "monospace",
180
+ textAlign: "center",
181
+ margin: "24px 0"
182
+ }
183
+ };
184
+
185
+ // src/emails/MagicLink.tsx
186
+ var import_jsx_runtime = require("react/jsx-runtime");
187
+ var MagicLinkEmail = ({
188
+ magicLink,
189
+ email,
190
+ siteName = "Newsletter",
191
+ expiresIn = "24 hours"
192
+ }) => {
193
+ const previewText = `Sign in to ${siteName}`;
194
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Html, { children: [
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Head, {}),
196
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Preview, { children: previewText }),
197
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Body, { style: styles.main, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Container, { style: styles.container, children: [
198
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.heading, children: [
199
+ "Sign in to ",
200
+ siteName
201
+ ] }),
202
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.text, children: [
203
+ "Hi ",
204
+ email.split("@")[0],
205
+ ","
206
+ ] }),
207
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.text, children: [
208
+ "We received a request to sign in to your ",
209
+ siteName,
210
+ " account. Click the button below to complete your sign in:"
211
+ ] }),
212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Button, { href: magicLink, style: styles.button, children: [
213
+ "Sign in to ",
214
+ siteName
215
+ ] }),
216
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Text, { style: styles.text, children: "Or copy and paste this URL into your browser:" }),
217
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: styles.code, children: magicLink }),
218
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Hr, { style: styles.hr }),
219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.footer, children: [
220
+ "This link will expire in ",
221
+ expiresIn,
222
+ ". If you didn't request this email, you can safely ignore it."
223
+ ] })
224
+ ] }) })
225
+ ] });
226
+ };
227
+
228
+ // src/emails/Welcome.tsx
229
+ var import_components2 = require("@react-email/components");
230
+ var import_jsx_runtime2 = require("react/jsx-runtime");
231
+ var WelcomeEmail = ({
232
+ email,
233
+ siteName = "Newsletter",
234
+ preferencesUrl
235
+ }) => {
236
+ const previewText = `Welcome to ${siteName}!`;
237
+ const firstName = email.split("@")[0];
238
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Html, { children: [
239
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Head, {}),
240
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Preview, { children: previewText }),
241
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Body, { style: styles.main, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Container, { style: styles.container, children: [
242
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.heading, children: [
243
+ "Welcome to ",
244
+ siteName,
245
+ "! \u{1F389}"
246
+ ] }),
247
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.text, children: [
248
+ "Hi ",
249
+ firstName,
250
+ ","
251
+ ] }),
252
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.text, children: [
253
+ "Thanks for subscribing to ",
254
+ siteName,
255
+ "! We're excited to have you as part of our community."
256
+ ] }),
257
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Text, { style: styles.text, children: "You'll receive our newsletter based on your preferences. Speaking of which, you can update your preferences anytime:" }),
258
+ preferencesUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Button, { href: preferencesUrl, style: styles.button, children: "Manage Preferences" }),
259
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Text, { style: styles.text, children: "Here's what you can expect from us:" }),
260
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.text, children: [
261
+ "\u2022 Regular updates based on your chosen frequency",
262
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
263
+ "\u2022 Content tailored to your interests",
264
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
265
+ "\u2022 Easy unsubscribe options in every email",
266
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
267
+ "\u2022 Your privacy respected always"
268
+ ] }),
269
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Hr, { style: styles.hr }),
270
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Text, { style: styles.footer, children: "If you have any questions, feel free to reply to this email. We're here to help!" })
271
+ ] }) })
272
+ ] });
273
+ };
274
+
275
+ // src/emails/SignIn.tsx
276
+ var import_jsx_runtime3 = require("react/jsx-runtime");
277
+ var SignInEmail = (props) => {
278
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MagicLinkEmail, { ...props });
279
+ };
280
+
281
+ // src/emails/render.tsx
282
+ var import_jsx_runtime4 = require("react/jsx-runtime");
283
+ async function renderEmail(template, data) {
284
+ try {
285
+ switch (template) {
286
+ case "magic-link": {
287
+ const magicLinkData = data;
288
+ return (0, import_render.render)(
289
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
290
+ MagicLinkEmail,
291
+ {
292
+ magicLink: magicLinkData.magicLink || magicLinkData.verificationUrl || magicLinkData.magicLinkUrl || "",
293
+ email: magicLinkData.email || "",
294
+ siteName: magicLinkData.siteName,
295
+ expiresIn: magicLinkData.expiresIn
296
+ }
297
+ )
298
+ );
299
+ }
300
+ case "signin": {
301
+ const signinData = data;
302
+ return (0, import_render.render)(
303
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
304
+ SignInEmail,
305
+ {
306
+ magicLink: signinData.magicLink || signinData.verificationUrl || signinData.magicLinkUrl || "",
307
+ email: signinData.email || "",
308
+ siteName: signinData.siteName,
309
+ expiresIn: signinData.expiresIn
310
+ }
311
+ )
312
+ );
313
+ }
314
+ case "welcome": {
315
+ const welcomeData = data;
316
+ return (0, import_render.render)(
317
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
318
+ WelcomeEmail,
319
+ {
320
+ email: welcomeData.email || "",
321
+ siteName: welcomeData.siteName,
322
+ preferencesUrl: welcomeData.preferencesUrl
323
+ }
324
+ )
325
+ );
326
+ }
327
+ default:
328
+ throw new Error(`Unknown email template: ${template}`);
329
+ }
330
+ } catch (error) {
331
+ console.error(`Failed to render email template ${template}:`, error);
332
+ throw error;
333
+ }
334
+ }
335
+
104
336
  // src/collections/Subscribers.ts
105
337
  var createSubscribersCollection = (pluginConfig) => {
106
338
  const slug = pluginConfig.subscribersSlug || "subscribers";
@@ -310,7 +542,24 @@ var createSubscribersCollection = (pluginConfig) => {
310
542
  }
311
543
  if (doc.subscriptionStatus === "active" && emailService) {
312
544
  try {
313
- } catch {
545
+ const settings = await req.payload.findGlobal({
546
+ slug: pluginConfig.settingsSlug || "newsletter-settings"
547
+ });
548
+ const serverURL = req.payload.config.serverURL || process.env.PAYLOAD_PUBLIC_SERVER_URL || "";
549
+ const html = await renderEmail("welcome", {
550
+ email: doc.email,
551
+ siteName: settings?.brandSettings?.siteName || "Newsletter",
552
+ preferencesUrl: `${serverURL}/account/preferences`
553
+ // This could be customized
554
+ });
555
+ await emailService.send({
556
+ to: doc.email,
557
+ subject: settings?.brandSettings?.siteName ? `Welcome to ${settings.brandSettings.siteName}!` : "Welcome!",
558
+ html
559
+ });
560
+ console.log(`Welcome email sent to: ${doc.email}`);
561
+ } catch (error) {
562
+ console.error("Failed to send welcome email:", error);
314
563
  }
315
564
  }
316
565
  if (pluginConfig.hooks?.afterSubscribe) {
@@ -1195,238 +1444,6 @@ function generateMagicLinkURL(token, baseURL, config) {
1195
1444
  return url.toString();
1196
1445
  }
1197
1446
 
1198
- // src/emails/render.tsx
1199
- var import_render = require("@react-email/render");
1200
-
1201
- // src/emails/MagicLink.tsx
1202
- var import_components = require("@react-email/components");
1203
-
1204
- // src/emails/styles.ts
1205
- var styles = {
1206
- main: {
1207
- backgroundColor: "#f6f9fc",
1208
- fontFamily: '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif'
1209
- },
1210
- container: {
1211
- backgroundColor: "#ffffff",
1212
- border: "1px solid #f0f0f0",
1213
- borderRadius: "5px",
1214
- margin: "0 auto",
1215
- padding: "45px",
1216
- marginBottom: "64px",
1217
- maxWidth: "500px"
1218
- },
1219
- heading: {
1220
- fontSize: "24px",
1221
- letterSpacing: "-0.5px",
1222
- lineHeight: "1.3",
1223
- fontWeight: "600",
1224
- color: "#484848",
1225
- margin: "0 0 20px",
1226
- padding: "0"
1227
- },
1228
- text: {
1229
- fontSize: "16px",
1230
- lineHeight: "26px",
1231
- fontWeight: "400",
1232
- color: "#484848",
1233
- margin: "16px 0"
1234
- },
1235
- button: {
1236
- backgroundColor: "#000000",
1237
- borderRadius: "5px",
1238
- color: "#fff",
1239
- fontSize: "16px",
1240
- fontWeight: "bold",
1241
- textDecoration: "none",
1242
- textAlign: "center",
1243
- display: "block",
1244
- width: "100%",
1245
- padding: "14px 20px",
1246
- margin: "30px 0"
1247
- },
1248
- link: {
1249
- color: "#2754C5",
1250
- fontSize: "14px",
1251
- textDecoration: "underline",
1252
- wordBreak: "break-all"
1253
- },
1254
- hr: {
1255
- borderColor: "#e6ebf1",
1256
- margin: "30px 0"
1257
- },
1258
- footer: {
1259
- fontSize: "14px",
1260
- lineHeight: "24px",
1261
- color: "#9ca2ac",
1262
- textAlign: "center",
1263
- margin: "0"
1264
- },
1265
- code: {
1266
- display: "inline-block",
1267
- padding: "16px",
1268
- width: "100%",
1269
- backgroundColor: "#f4f4f4",
1270
- borderRadius: "5px",
1271
- border: "1px solid #eee",
1272
- fontSize: "14px",
1273
- fontFamily: "monospace",
1274
- textAlign: "center",
1275
- margin: "24px 0"
1276
- }
1277
- };
1278
-
1279
- // src/emails/MagicLink.tsx
1280
- var import_jsx_runtime = require("react/jsx-runtime");
1281
- var MagicLinkEmail = ({
1282
- magicLink,
1283
- email,
1284
- siteName = "Newsletter",
1285
- expiresIn = "24 hours"
1286
- }) => {
1287
- const previewText = `Sign in to ${siteName}`;
1288
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Html, { children: [
1289
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Head, {}),
1290
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Preview, { children: previewText }),
1291
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Body, { style: styles.main, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Container, { style: styles.container, children: [
1292
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.heading, children: [
1293
- "Sign in to ",
1294
- siteName
1295
- ] }),
1296
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.text, children: [
1297
- "Hi ",
1298
- email.split("@")[0],
1299
- ","
1300
- ] }),
1301
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.text, children: [
1302
- "We received a request to sign in to your ",
1303
- siteName,
1304
- " account. Click the button below to complete your sign in:"
1305
- ] }),
1306
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Button, { href: magicLink, style: styles.button, children: [
1307
- "Sign in to ",
1308
- siteName
1309
- ] }),
1310
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Text, { style: styles.text, children: "Or copy and paste this URL into your browser:" }),
1311
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: styles.code, children: magicLink }),
1312
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Hr, { style: styles.hr }),
1313
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { style: styles.footer, children: [
1314
- "This link will expire in ",
1315
- expiresIn,
1316
- ". If you didn't request this email, you can safely ignore it."
1317
- ] })
1318
- ] }) })
1319
- ] });
1320
- };
1321
-
1322
- // src/emails/Welcome.tsx
1323
- var import_components2 = require("@react-email/components");
1324
- var import_jsx_runtime2 = require("react/jsx-runtime");
1325
- var WelcomeEmail = ({
1326
- email,
1327
- siteName = "Newsletter",
1328
- preferencesUrl
1329
- }) => {
1330
- const previewText = `Welcome to ${siteName}!`;
1331
- const firstName = email.split("@")[0];
1332
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Html, { children: [
1333
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Head, {}),
1334
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Preview, { children: previewText }),
1335
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Body, { style: styles.main, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Container, { style: styles.container, children: [
1336
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.heading, children: [
1337
- "Welcome to ",
1338
- siteName,
1339
- "! \u{1F389}"
1340
- ] }),
1341
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.text, children: [
1342
- "Hi ",
1343
- firstName,
1344
- ","
1345
- ] }),
1346
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.text, children: [
1347
- "Thanks for subscribing to ",
1348
- siteName,
1349
- "! We're excited to have you as part of our community."
1350
- ] }),
1351
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Text, { style: styles.text, children: "You'll receive our newsletter based on your preferences. Speaking of which, you can update your preferences anytime:" }),
1352
- preferencesUrl && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Button, { href: preferencesUrl, style: styles.button, children: "Manage Preferences" }),
1353
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Text, { style: styles.text, children: "Here's what you can expect from us:" }),
1354
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_components2.Text, { style: styles.text, children: [
1355
- "\u2022 Regular updates based on your chosen frequency",
1356
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
1357
- "\u2022 Content tailored to your interests",
1358
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
1359
- "\u2022 Easy unsubscribe options in every email",
1360
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("br", {}),
1361
- "\u2022 Your privacy respected always"
1362
- ] }),
1363
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Hr, { style: styles.hr }),
1364
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_components2.Text, { style: styles.footer, children: "If you have any questions, feel free to reply to this email. We're here to help!" })
1365
- ] }) })
1366
- ] });
1367
- };
1368
-
1369
- // src/emails/SignIn.tsx
1370
- var import_jsx_runtime3 = require("react/jsx-runtime");
1371
- var SignInEmail = (props) => {
1372
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MagicLinkEmail, { ...props });
1373
- };
1374
-
1375
- // src/emails/render.tsx
1376
- var import_jsx_runtime4 = require("react/jsx-runtime");
1377
- async function renderEmail(template, data) {
1378
- try {
1379
- switch (template) {
1380
- case "magic-link": {
1381
- const magicLinkData = data;
1382
- return (0, import_render.render)(
1383
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1384
- MagicLinkEmail,
1385
- {
1386
- magicLink: magicLinkData.magicLink || magicLinkData.verificationUrl || magicLinkData.magicLinkUrl || "",
1387
- email: magicLinkData.email || "",
1388
- siteName: magicLinkData.siteName,
1389
- expiresIn: magicLinkData.expiresIn
1390
- }
1391
- )
1392
- );
1393
- }
1394
- case "signin": {
1395
- const signinData = data;
1396
- return (0, import_render.render)(
1397
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1398
- SignInEmail,
1399
- {
1400
- magicLink: signinData.magicLink || signinData.verificationUrl || signinData.magicLinkUrl || "",
1401
- email: signinData.email || "",
1402
- siteName: signinData.siteName,
1403
- expiresIn: signinData.expiresIn
1404
- }
1405
- )
1406
- );
1407
- }
1408
- case "welcome": {
1409
- const welcomeData = data;
1410
- return (0, import_render.render)(
1411
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1412
- WelcomeEmail,
1413
- {
1414
- email: welcomeData.email || "",
1415
- siteName: welcomeData.siteName,
1416
- preferencesUrl: welcomeData.preferencesUrl
1417
- }
1418
- )
1419
- );
1420
- }
1421
- default:
1422
- throw new Error(`Unknown email template: ${template}`);
1423
- }
1424
- } catch (error) {
1425
- console.error(`Failed to render email template ${template}:`, error);
1426
- throw error;
1427
- }
1428
- }
1429
-
1430
1447
  // src/endpoints/subscribe.ts
1431
1448
  var createSubscribeEndpoint = (config) => {
1432
1449
  return {