payload-plugin-newsletter 0.15.1 → 0.16.1

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,3 +1,55 @@
1
+ ## [0.16.1] - 2025-07-27
2
+
3
+ ### Fixed
4
+ - **Critical Bug Fix** - Fixed afterChange hook placement for sending broadcasts
5
+ - The send hook was incorrectly placed in the `afterDelete` array instead of `afterChange`
6
+ - This prevented broadcasts from being sent when published
7
+ - Publishing broadcasts now correctly triggers the send functionality
8
+
9
+ ## [0.16.0] - 2025-07-27
10
+
11
+ ### Changed
12
+ - **Send = Publish Workflow** - Simplified broadcast sending to use Payload's native draft/publish system
13
+ - Publishing a broadcast now automatically sends it via the configured email provider
14
+ - Removed custom Send/Schedule modal in favor of Payload's built-in UI
15
+ - Scheduled publishing supported via Payload's Jobs Queue system
16
+ - Breaking: Removed `SendBroadcastModal` and `ActionsCell` components
17
+ - **Streamlined UI** - Removed custom action buttons from broadcasts list view
18
+ - Users now use standard Payload publish/schedule functionality
19
+ - Cleaner interface that follows Payload's patterns
20
+ - Less code to maintain while providing better integration
21
+
22
+ ### Added
23
+ - **Automatic Send on Publish** - New `afterChange` hook that sends broadcasts when published
24
+ - Checks if broadcast is transitioning to published status
25
+ - Automatically calls provider's send method
26
+ - Updates broadcast status to "sending" after successful send
27
+ - Handles failures gracefully with status update to "failed"
28
+ - **Jobs Queue Documentation** - Added comprehensive setup instructions for scheduled publishing
29
+ - Vercel Cron configuration example
30
+ - Security setup with CRON_SECRET
31
+ - Step-by-step guide for enabling scheduled broadcasts
32
+
33
+ ### Removed
34
+ - **Custom UI Components** (Breaking Change)
35
+ - `SendBroadcastModal` - Custom send/schedule modal
36
+ - `ActionsCell` - Custom action buttons in list view
37
+ - `actions` field from Broadcasts collection
38
+ - These are replaced by Payload's native publish/schedule functionality
39
+
40
+ ### Technical
41
+ - Enabled `versions` configuration on Broadcasts collection with drafts and scheduled publishing
42
+ - Updated default columns to show both `_status` (Draft/Published) and `status` (send status)
43
+ - Improved TypeScript exports by removing deleted component references
44
+ - All tests passing with minor version upgrade
45
+
46
+ ### Migration Guide
47
+ If you were using the custom Send/Schedule modal:
48
+ 1. The functionality is now built into Payload's publish system
49
+ 2. To send immediately: Click "Publish"
50
+ 3. To schedule: Click "Schedule" (requires Jobs Queue setup)
51
+ 4. Remove any imports of `SendBroadcastModal` or `ActionsCell` from your code
52
+
1
53
  ## [0.15.1] - 2025-07-27
2
54
 
3
55
  ### Fixed
package/README.md CHANGED
@@ -241,6 +241,50 @@ This adds a `broadcasts` collection with:
241
241
  - Custom email blocks (buttons, dividers)
242
242
  - Inline email preview with React Email
243
243
  - Automatic sync with your email provider
244
+ - Draft/publish system with scheduled publishing support
245
+
246
+ ### Send = Publish Workflow
247
+
248
+ The plugin integrates seamlessly with Payload's draft/publish system:
249
+
250
+ - **Draft**: Create and edit broadcasts without sending
251
+ - **Publish**: Publishing a broadcast automatically sends it via your configured email provider
252
+ - **Schedule**: Use Payload's scheduled publishing to send broadcasts at a future time
253
+
254
+ **How it works:**
255
+ 1. Create a broadcast and save as draft
256
+ 2. When ready, click "Publish" to send immediately
257
+ 3. Or use "Schedule" to publish (and send) at a specific date/time
258
+
259
+ **Important**: Scheduled publishing requires configuring Payload's Jobs Queue. For Vercel deployments, add this to your `vercel.json`:
260
+
261
+ ```json
262
+ {
263
+ "crons": [
264
+ {
265
+ "path": "/api/payload-jobs/run",
266
+ "schedule": "*/5 * * * *"
267
+ }
268
+ ]
269
+ }
270
+ ```
271
+
272
+ And secure the endpoint in your `payload.config.ts`:
273
+
274
+ ```typescript
275
+ export default buildConfig({
276
+ // ... other config
277
+ jobs: {
278
+ access: {
279
+ run: ({ req }) => {
280
+ if (req.user) return true
281
+ const authHeader = req.headers.get('authorization')
282
+ return authHeader === `Bearer ${process.env.CRON_SECRET}`
283
+ },
284
+ },
285
+ },
286
+ })
287
+ ```
244
288
 
245
289
  ### Custom Email Templates (v0.12.0+)
246
290
 
@@ -1168,6 +1168,12 @@ var createBroadcastsCollection = (pluginConfig) => {
1168
1168
  const customizations = pluginConfig.customizations?.broadcasts;
1169
1169
  return {
1170
1170
  slug: "broadcasts",
1171
+ versions: {
1172
+ drafts: {
1173
+ autosave: true,
1174
+ schedulePublish: true
1175
+ }
1176
+ },
1171
1177
  labels: {
1172
1178
  singular: "Broadcast",
1173
1179
  plural: "Broadcasts"
@@ -1175,7 +1181,7 @@ var createBroadcastsCollection = (pluginConfig) => {
1175
1181
  admin: {
1176
1182
  useAsTitle: "subject",
1177
1183
  description: "Individual email campaigns sent to subscribers",
1178
- defaultColumns: ["subject", "status", "sentAt", "recipientCount", "actions"]
1184
+ defaultColumns: ["subject", "_status", "status", "sentAt", "recipientCount"]
1179
1185
  },
1180
1186
  fields: [
1181
1187
  {
@@ -1388,18 +1394,6 @@ var createBroadcastsCollection = (pluginConfig) => {
1388
1394
  condition: () => false
1389
1395
  // Hidden by default
1390
1396
  }
1391
- },
1392
- // UI Field for custom actions in list view
1393
- {
1394
- name: "actions",
1395
- type: "ui",
1396
- admin: {
1397
- components: {
1398
- Cell: "payload-plugin-newsletter/components#ActionsCell",
1399
- Field: "payload-plugin-newsletter/components#EmptyField"
1400
- },
1401
- disableListColumn: false
1402
- }
1403
1397
  }
1404
1398
  ],
1405
1399
  hooks: {
@@ -1445,6 +1439,51 @@ var createBroadcastsCollection = (pluginConfig) => {
1445
1439
  req.payload.logger.error("Failed to create broadcast in provider:", error);
1446
1440
  return doc;
1447
1441
  }
1442
+ },
1443
+ // Hook to send when published
1444
+ async ({ doc, operation, previousDoc, req }) => {
1445
+ if (operation !== "update") return doc;
1446
+ const wasUnpublished = !previousDoc?._status || previousDoc._status === "draft";
1447
+ const isNowPublished = doc._status === "published";
1448
+ if (wasUnpublished && isNowPublished && doc.providerId) {
1449
+ if (doc.status === "sent" || doc.status === "sending") {
1450
+ return doc;
1451
+ }
1452
+ try {
1453
+ const broadcastConfig = pluginConfig.providers?.broadcast;
1454
+ const resendConfig = pluginConfig.providers?.resend;
1455
+ if (!broadcastConfig && !resendConfig) {
1456
+ req.payload.logger.error("No provider configured for sending");
1457
+ return doc;
1458
+ }
1459
+ if (broadcastConfig) {
1460
+ const { BroadcastApiProvider: BroadcastApiProvider2 } = await Promise.resolve().then(() => (init_broadcast2(), broadcast_exports));
1461
+ const provider = new BroadcastApiProvider2(broadcastConfig);
1462
+ await provider.send(doc.providerId);
1463
+ }
1464
+ await req.payload.update({
1465
+ collection: "broadcasts",
1466
+ id: doc.id,
1467
+ data: {
1468
+ status: "sending" /* SENDING */,
1469
+ sentAt: (/* @__PURE__ */ new Date()).toISOString()
1470
+ },
1471
+ req
1472
+ });
1473
+ req.payload.logger.info(`Broadcast ${doc.id} sent successfully`);
1474
+ } catch (error) {
1475
+ req.payload.logger.error(`Failed to send broadcast ${doc.id}:`, error);
1476
+ await req.payload.update({
1477
+ collection: "broadcasts",
1478
+ id: doc.id,
1479
+ data: {
1480
+ status: "failed" /* FAILED */
1481
+ },
1482
+ req
1483
+ });
1484
+ }
1485
+ }
1486
+ return doc;
1448
1487
  }
1449
1488
  ],
1450
1489
  // Sync updates with provider