payload-plugin-newsletter 0.1.1 → 0.3.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 +56 -0
- package/README.md +61 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/collections/NewsletterSettings.d.ts +4 -0
- package/dist/collections/NewsletterSettings.d.ts.map +1 -0
- package/dist/collections/Subscribers.d.ts.map +1 -1
- package/dist/endpoints/preferences.d.ts.map +1 -1
- package/dist/endpoints/subscribe.d.ts.map +1 -1
- package/dist/endpoints/unsubscribe.d.ts.map +1 -1
- package/dist/endpoints/verify-magic-link.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/src/collections/NewsletterSettings.js +390 -0
- package/dist/src/collections/NewsletterSettings.js.map +1 -0
- package/dist/src/collections/Subscribers.js +4 -39
- package/dist/src/collections/Subscribers.js.map +1 -1
- package/dist/src/components/MagicLinkVerify.js +1 -1
- package/dist/src/components/MagicLinkVerify.js.map +1 -1
- package/dist/src/endpoints/preferences.js +16 -4
- package/dist/src/endpoints/preferences.js.map +1 -1
- package/dist/src/endpoints/subscribe.js +14 -3
- package/dist/src/endpoints/subscribe.js.map +1 -1
- package/dist/src/endpoints/unsubscribe.js +10 -2
- package/dist/src/endpoints/unsubscribe.js.map +1 -1
- package/dist/src/endpoints/verify-magic-link.js +13 -3
- package/dist/src/endpoints/verify-magic-link.js.map +1 -1
- package/dist/src/index.js +18 -12
- package/dist/src/index.js.map +1 -1
- package/dist/src/templates/NewsletterTemplate.js.map +1 -1
- package/dist/src/templates/WelcomeTemplate.js.map +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/utils/access.js +56 -0
- package/dist/src/utils/access.js.map +1 -0
- package/dist/templates/NewsletterTemplate.d.ts.map +1 -1
- package/dist/templates/WelcomeTemplate.d.ts.map +1 -1
- package/dist/types/index.d.ts +16 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/access.d.ts +15 -0
- package/dist/utils/access.d.ts.map +1 -0
- package/package.json +7 -3
- package/CLAUDE.md +0 -110
- package/dist/globals/EmailSettings.d.ts +0 -4
- package/dist/globals/EmailSettings.d.ts.map +0 -1
- package/dist/src/globals/EmailSettings.js +0 -252
- package/dist/src/globals/EmailSettings.js.map +0 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CollectionConfig } from 'payload';
|
|
2
|
+
import type { NewsletterPluginConfig } from '../types';
|
|
3
|
+
export declare const createNewsletterSettingsCollection: (pluginConfig: NewsletterPluginConfig) => CollectionConfig;
|
|
4
|
+
//# sourceMappingURL=NewsletterSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NewsletterSettings.d.ts","sourceRoot":"","sources":["../../src/collections/NewsletterSettings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,eAAO,MAAM,kCAAkC,GAC7C,cAAc,sBAAsB,KACnC,gBAiXF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Subscribers.d.ts","sourceRoot":"","sources":["../../src/collections/Subscribers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"Subscribers.d.ts","sourceRoot":"","sources":["../../src/collections/Subscribers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAgE,MAAM,SAAS,CAAA;AAC7G,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,eAAO,MAAM,2BAA2B,GACtC,cAAc,sBAAsB,KACnC,gBA4SF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../src/endpoints/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,sBAAsB,KAC7B,
|
|
1
|
+
{"version":3,"file":"preferences.d.ts","sourceRoot":"","sources":["../../src/endpoints/preferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,sBAAsB,KAC7B,QAmEF,CAAA;AAED,eAAO,MAAM,+BAA+B,GAC1C,QAAQ,sBAAsB,KAC7B,QA8EF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["../../src/endpoints/subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"subscribe.d.ts","sourceRoot":"","sources":["../../src/endpoints/subscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAQtD,eAAO,MAAM,uBAAuB,GAClC,QAAQ,sBAAsB,KAC7B,QAgLF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsubscribe.d.ts","sourceRoot":"","sources":["../../src/endpoints/unsubscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,sBAAsB,KAC7B,
|
|
1
|
+
{"version":3,"file":"unsubscribe.d.ts","sourceRoot":"","sources":["../../src/endpoints/unsubscribe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAGtD,eAAO,MAAM,yBAAyB,GACpC,QAAQ,sBAAsB,KAC7B,QAoHF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify-magic-link.d.ts","sourceRoot":"","sources":["../../src/endpoints/verify-magic-link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAMtD,eAAO,MAAM,6BAA6B,GACxC,QAAQ,sBAAsB,KAC7B,
|
|
1
|
+
{"version":3,"file":"verify-magic-link.d.ts","sourceRoot":"","sources":["../../src/endpoints/verify-magic-link.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAkB,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAMtD,eAAO,MAAM,6BAA6B,GACxC,QAAQ,sBAAsB,KAC7B,QAkHF,CAAA"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAQrD,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,WAAW;QACnB,sBAAsB,CAAC,EAAE,GAAG,CAAA;KAC7B;CACF;AAED,eAAO,MAAM,gBAAgB,GAAI,cAAc,sBAAsB,MAAM,gBAAgB,MAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACrC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAQrD,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,WAAW;QACnB,sBAAsB,CAAC,EAAE,GAAG,CAAA;KAC7B;CACF;AAED,eAAO,MAAM,gBAAgB,GAAI,cAAc,sBAAsB,MAAM,gBAAgB,MAAM,KAAG,MAiInG,CAAA;AAED,OAAO,EAAE,gBAAgB,IAAI,OAAO,EAAE,CAAA"}
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { adminOnly } from '../utils/access';
|
|
2
|
+
export const createNewsletterSettingsCollection = (pluginConfig)=>{
|
|
3
|
+
const slug = pluginConfig.settingsSlug || 'newsletter-settings';
|
|
4
|
+
return {
|
|
5
|
+
slug,
|
|
6
|
+
labels: {
|
|
7
|
+
singular: 'Newsletter Setting',
|
|
8
|
+
plural: 'Newsletter Settings'
|
|
9
|
+
},
|
|
10
|
+
admin: {
|
|
11
|
+
useAsTitle: 'name',
|
|
12
|
+
defaultColumns: [
|
|
13
|
+
'name',
|
|
14
|
+
'provider',
|
|
15
|
+
'active',
|
|
16
|
+
'updatedAt'
|
|
17
|
+
],
|
|
18
|
+
group: 'Newsletter',
|
|
19
|
+
description: 'Configure email provider settings and templates'
|
|
20
|
+
},
|
|
21
|
+
fields: [
|
|
22
|
+
{
|
|
23
|
+
name: 'name',
|
|
24
|
+
type: 'text',
|
|
25
|
+
label: 'Configuration Name',
|
|
26
|
+
required: true,
|
|
27
|
+
admin: {
|
|
28
|
+
description: 'A descriptive name for this configuration (e.g., "Production", "Development", "Marketing Emails")'
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'active',
|
|
33
|
+
type: 'checkbox',
|
|
34
|
+
label: 'Active',
|
|
35
|
+
defaultValue: false,
|
|
36
|
+
admin: {
|
|
37
|
+
description: 'Only one configuration can be active at a time'
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: 'tabs',
|
|
42
|
+
tabs: [
|
|
43
|
+
{
|
|
44
|
+
label: 'Provider Settings',
|
|
45
|
+
fields: [
|
|
46
|
+
{
|
|
47
|
+
name: 'provider',
|
|
48
|
+
type: 'select',
|
|
49
|
+
label: 'Email Provider',
|
|
50
|
+
required: true,
|
|
51
|
+
options: [
|
|
52
|
+
{
|
|
53
|
+
label: 'Resend',
|
|
54
|
+
value: 'resend'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'Broadcast (Self-Hosted)',
|
|
58
|
+
value: 'broadcast'
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
defaultValue: pluginConfig.providers.default,
|
|
62
|
+
admin: {
|
|
63
|
+
description: 'Choose which email service to use'
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'resendSettings',
|
|
68
|
+
type: 'group',
|
|
69
|
+
label: 'Resend Settings',
|
|
70
|
+
admin: {
|
|
71
|
+
condition: (data)=>data?.provider === 'resend'
|
|
72
|
+
},
|
|
73
|
+
fields: [
|
|
74
|
+
{
|
|
75
|
+
name: 'apiKey',
|
|
76
|
+
type: 'text',
|
|
77
|
+
label: 'API Key',
|
|
78
|
+
required: true,
|
|
79
|
+
admin: {
|
|
80
|
+
description: 'Your Resend API key'
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'audienceIds',
|
|
85
|
+
type: 'array',
|
|
86
|
+
label: 'Audience IDs by Locale',
|
|
87
|
+
fields: [
|
|
88
|
+
{
|
|
89
|
+
name: 'locale',
|
|
90
|
+
type: 'select',
|
|
91
|
+
label: 'Locale',
|
|
92
|
+
required: true,
|
|
93
|
+
options: pluginConfig.i18n?.locales?.map((locale)=>({
|
|
94
|
+
label: locale.toUpperCase(),
|
|
95
|
+
value: locale
|
|
96
|
+
})) || [
|
|
97
|
+
{
|
|
98
|
+
label: 'EN',
|
|
99
|
+
value: 'en'
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'production',
|
|
105
|
+
type: 'text',
|
|
106
|
+
label: 'Production Audience ID'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'development',
|
|
110
|
+
type: 'text',
|
|
111
|
+
label: 'Development Audience ID'
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'broadcastSettings',
|
|
119
|
+
type: 'group',
|
|
120
|
+
label: 'Broadcast Settings',
|
|
121
|
+
admin: {
|
|
122
|
+
condition: (data)=>data?.provider === 'broadcast'
|
|
123
|
+
},
|
|
124
|
+
fields: [
|
|
125
|
+
{
|
|
126
|
+
name: 'apiUrl',
|
|
127
|
+
type: 'text',
|
|
128
|
+
label: 'API URL',
|
|
129
|
+
required: true,
|
|
130
|
+
admin: {
|
|
131
|
+
description: 'Your Broadcast instance URL'
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'productionToken',
|
|
136
|
+
type: 'text',
|
|
137
|
+
label: 'Production Token',
|
|
138
|
+
admin: {
|
|
139
|
+
description: 'Token for production environment'
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
name: 'developmentToken',
|
|
144
|
+
type: 'text',
|
|
145
|
+
label: 'Development Token',
|
|
146
|
+
admin: {
|
|
147
|
+
description: 'Token for development environment'
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: 'fromAddress',
|
|
154
|
+
type: 'email',
|
|
155
|
+
label: 'From Address',
|
|
156
|
+
required: true,
|
|
157
|
+
admin: {
|
|
158
|
+
description: 'Default sender email address'
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: 'fromName',
|
|
163
|
+
type: 'text',
|
|
164
|
+
label: 'From Name',
|
|
165
|
+
required: true,
|
|
166
|
+
admin: {
|
|
167
|
+
description: 'Default sender name'
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'replyTo',
|
|
172
|
+
type: 'email',
|
|
173
|
+
label: 'Reply-To Address',
|
|
174
|
+
admin: {
|
|
175
|
+
description: 'Optional reply-to email address'
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
label: 'Email Templates',
|
|
182
|
+
fields: [
|
|
183
|
+
{
|
|
184
|
+
name: 'emailTemplates',
|
|
185
|
+
type: 'group',
|
|
186
|
+
label: 'Email Templates',
|
|
187
|
+
fields: [
|
|
188
|
+
{
|
|
189
|
+
name: 'welcome',
|
|
190
|
+
type: 'group',
|
|
191
|
+
label: 'Welcome Email',
|
|
192
|
+
fields: [
|
|
193
|
+
{
|
|
194
|
+
name: 'enabled',
|
|
195
|
+
type: 'checkbox',
|
|
196
|
+
label: 'Send Welcome Email',
|
|
197
|
+
defaultValue: true
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: 'subject',
|
|
201
|
+
type: 'text',
|
|
202
|
+
label: 'Subject Line',
|
|
203
|
+
defaultValue: 'Welcome to {{fromName}}!',
|
|
204
|
+
admin: {
|
|
205
|
+
condition: (data)=>data?.emailTemplates?.welcome?.enabled
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'preheader',
|
|
210
|
+
type: 'text',
|
|
211
|
+
label: 'Preheader Text',
|
|
212
|
+
admin: {
|
|
213
|
+
condition: (data)=>data?.emailTemplates?.welcome?.enabled
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'magicLink',
|
|
220
|
+
type: 'group',
|
|
221
|
+
label: 'Magic Link Email',
|
|
222
|
+
fields: [
|
|
223
|
+
{
|
|
224
|
+
name: 'subject',
|
|
225
|
+
type: 'text',
|
|
226
|
+
label: 'Subject Line',
|
|
227
|
+
defaultValue: 'Sign in to {{fromName}}'
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'preheader',
|
|
231
|
+
type: 'text',
|
|
232
|
+
label: 'Preheader Text',
|
|
233
|
+
defaultValue: 'Click the link to access your preferences'
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: 'expirationTime',
|
|
237
|
+
type: 'select',
|
|
238
|
+
label: 'Link Expiration',
|
|
239
|
+
defaultValue: '7d',
|
|
240
|
+
options: [
|
|
241
|
+
{
|
|
242
|
+
label: '1 hour',
|
|
243
|
+
value: '1h'
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
label: '24 hours',
|
|
247
|
+
value: '24h'
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
label: '7 days',
|
|
251
|
+
value: '7d'
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
label: '30 days',
|
|
255
|
+
value: '30d'
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
}
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
label: 'Subscription Settings',
|
|
267
|
+
fields: [
|
|
268
|
+
{
|
|
269
|
+
name: 'subscriptionSettings',
|
|
270
|
+
type: 'group',
|
|
271
|
+
label: 'Subscription Settings',
|
|
272
|
+
fields: [
|
|
273
|
+
{
|
|
274
|
+
name: 'requireDoubleOptIn',
|
|
275
|
+
type: 'checkbox',
|
|
276
|
+
label: 'Require Double Opt-In',
|
|
277
|
+
defaultValue: false,
|
|
278
|
+
admin: {
|
|
279
|
+
description: 'Require email confirmation before activating subscriptions'
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: 'allowedDomains',
|
|
284
|
+
type: 'array',
|
|
285
|
+
label: 'Allowed Email Domains',
|
|
286
|
+
admin: {
|
|
287
|
+
description: 'Leave empty to allow all domains'
|
|
288
|
+
},
|
|
289
|
+
fields: [
|
|
290
|
+
{
|
|
291
|
+
name: 'domain',
|
|
292
|
+
type: 'text',
|
|
293
|
+
label: 'Domain',
|
|
294
|
+
required: true,
|
|
295
|
+
admin: {
|
|
296
|
+
placeholder: 'example.com'
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'maxSubscribersPerIP',
|
|
303
|
+
type: 'number',
|
|
304
|
+
label: 'Max Subscribers per IP',
|
|
305
|
+
defaultValue: 10,
|
|
306
|
+
min: 1,
|
|
307
|
+
admin: {
|
|
308
|
+
description: 'Maximum number of subscriptions allowed from a single IP address'
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
],
|
|
318
|
+
hooks: {
|
|
319
|
+
beforeChange: [
|
|
320
|
+
async ({ data, req, operation })=>{
|
|
321
|
+
// Verify admin access for settings changes
|
|
322
|
+
if (!req.user || req.user.collection !== 'users') {
|
|
323
|
+
throw new Error('Only administrators can modify newsletter settings');
|
|
324
|
+
}
|
|
325
|
+
// If setting this config as active, deactivate all others
|
|
326
|
+
if (data?.active && operation !== 'create') {
|
|
327
|
+
await req.payload.update({
|
|
328
|
+
collection: slug,
|
|
329
|
+
where: {
|
|
330
|
+
id: {
|
|
331
|
+
not_equals: data.id
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
data: {
|
|
335
|
+
active: false
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
// For new configs, ensure only one is active
|
|
340
|
+
if (operation === 'create' && data?.active) {
|
|
341
|
+
const existingActive = await req.payload.find({
|
|
342
|
+
collection: slug,
|
|
343
|
+
where: {
|
|
344
|
+
active: {
|
|
345
|
+
equals: true
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
if (existingActive.docs.length > 0) {
|
|
350
|
+
// Deactivate existing active configs
|
|
351
|
+
for (const doc of existingActive.docs){
|
|
352
|
+
await req.payload.update({
|
|
353
|
+
collection: slug,
|
|
354
|
+
id: doc.id,
|
|
355
|
+
data: {
|
|
356
|
+
active: false
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return data;
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
afterChange: [
|
|
366
|
+
async ({ doc, req })=>{
|
|
367
|
+
// Reinitialize email service when settings change
|
|
368
|
+
if (req.payload.newsletterEmailService && doc.active) {
|
|
369
|
+
try {
|
|
370
|
+
// TODO: Implement email service reinitialization
|
|
371
|
+
console.warn('Newsletter settings updated, reinitializing service...');
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error('Failed to reinitialize email service:', error);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return doc;
|
|
377
|
+
}
|
|
378
|
+
]
|
|
379
|
+
},
|
|
380
|
+
access: {
|
|
381
|
+
read: ()=>true,
|
|
382
|
+
create: adminOnly(pluginConfig),
|
|
383
|
+
update: adminOnly(pluginConfig),
|
|
384
|
+
delete: adminOnly(pluginConfig)
|
|
385
|
+
},
|
|
386
|
+
timestamps: true
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
//# sourceMappingURL=NewsletterSettings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/collections/NewsletterSettings.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly } from '../utils/access'\n\nexport const createNewsletterSettingsCollection = (\n pluginConfig: NewsletterPluginConfig\n): CollectionConfig => {\n const slug = pluginConfig.settingsSlug || 'newsletter-settings'\n \n return {\n slug,\n labels: {\n singular: 'Newsletter Setting',\n plural: 'Newsletter Settings',\n },\n admin: {\n useAsTitle: 'name',\n defaultColumns: ['name', 'provider', 'active', 'updatedAt'],\n group: 'Newsletter',\n description: 'Configure email provider settings and templates',\n },\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Configuration Name',\n required: true,\n admin: {\n description: 'A descriptive name for this configuration (e.g., \"Production\", \"Development\", \"Marketing Emails\")',\n },\n },\n {\n name: 'active',\n type: 'checkbox',\n label: 'Active',\n defaultValue: false,\n admin: {\n description: 'Only one configuration can be active at a time',\n },\n },\n {\n type: 'tabs',\n tabs: [\n {\n label: 'Provider Settings',\n fields: [\n {\n name: 'provider',\n type: 'select',\n label: 'Email Provider',\n required: true,\n options: [\n { label: 'Resend', value: 'resend' },\n { label: 'Broadcast (Self-Hosted)', value: 'broadcast' },\n ],\n defaultValue: pluginConfig.providers.default,\n admin: {\n description: 'Choose which email service to use',\n },\n },\n {\n name: 'resendSettings',\n type: 'group',\n label: 'Resend Settings',\n admin: {\n condition: (data) => data?.provider === 'resend',\n },\n fields: [\n {\n name: 'apiKey',\n type: 'text',\n label: 'API Key',\n required: true,\n admin: {\n description: 'Your Resend API key',\n },\n },\n {\n name: 'audienceIds',\n type: 'array',\n label: 'Audience IDs by Locale',\n fields: [\n {\n name: 'locale',\n type: 'select',\n label: 'Locale',\n required: true,\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n },\n {\n name: 'production',\n type: 'text',\n label: 'Production Audience ID',\n },\n {\n name: 'development',\n type: 'text',\n label: 'Development Audience ID',\n },\n ],\n },\n ],\n },\n {\n name: 'broadcastSettings',\n type: 'group',\n label: 'Broadcast Settings',\n admin: {\n condition: (data) => data?.provider === 'broadcast',\n },\n fields: [\n {\n name: 'apiUrl',\n type: 'text',\n label: 'API URL',\n required: true,\n admin: {\n description: 'Your Broadcast instance URL',\n },\n },\n {\n name: 'productionToken',\n type: 'text',\n label: 'Production Token',\n admin: {\n description: 'Token for production environment',\n },\n },\n {\n name: 'developmentToken',\n type: 'text',\n label: 'Development Token',\n admin: {\n description: 'Token for development environment',\n },\n },\n ],\n },\n {\n name: 'fromAddress',\n type: 'email',\n label: 'From Address',\n required: true,\n admin: {\n description: 'Default sender email address',\n },\n },\n {\n name: 'fromName',\n type: 'text',\n label: 'From Name',\n required: true,\n admin: {\n description: 'Default sender name',\n },\n },\n {\n name: 'replyTo',\n type: 'email',\n label: 'Reply-To Address',\n admin: {\n description: 'Optional reply-to email address',\n },\n },\n ],\n },\n {\n label: 'Email Templates',\n fields: [\n {\n name: 'emailTemplates',\n type: 'group',\n label: 'Email Templates',\n fields: [\n {\n name: 'welcome',\n type: 'group',\n label: 'Welcome Email',\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n label: 'Send Welcome Email',\n defaultValue: true,\n },\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Welcome to {{fromName}}!',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n admin: {\n condition: (data) => data?.emailTemplates?.welcome?.enabled,\n },\n },\n ],\n },\n {\n name: 'magicLink',\n type: 'group',\n label: 'Magic Link Email',\n fields: [\n {\n name: 'subject',\n type: 'text',\n label: 'Subject Line',\n defaultValue: 'Sign in to {{fromName}}',\n },\n {\n name: 'preheader',\n type: 'text',\n label: 'Preheader Text',\n defaultValue: 'Click the link to access your preferences',\n },\n {\n name: 'expirationTime',\n type: 'select',\n label: 'Link Expiration',\n defaultValue: '7d',\n options: [\n { label: '1 hour', value: '1h' },\n { label: '24 hours', value: '24h' },\n { label: '7 days', value: '7d' },\n { label: '30 days', value: '30d' },\n ],\n },\n ],\n },\n ],\n },\n ],\n },\n {\n label: 'Subscription Settings',\n fields: [\n {\n name: 'subscriptionSettings',\n type: 'group',\n label: 'Subscription Settings',\n fields: [\n {\n name: 'requireDoubleOptIn',\n type: 'checkbox',\n label: 'Require Double Opt-In',\n defaultValue: false,\n admin: {\n description: 'Require email confirmation before activating subscriptions',\n },\n },\n {\n name: 'allowedDomains',\n type: 'array',\n label: 'Allowed Email Domains',\n admin: {\n description: 'Leave empty to allow all domains',\n },\n fields: [\n {\n name: 'domain',\n type: 'text',\n label: 'Domain',\n required: true,\n admin: {\n placeholder: 'example.com',\n },\n },\n ],\n },\n {\n name: 'maxSubscribersPerIP',\n type: 'number',\n label: 'Max Subscribers per IP',\n defaultValue: 10,\n min: 1,\n admin: {\n description: 'Maximum number of subscriptions allowed from a single IP address',\n },\n },\n ],\n },\n ],\n },\n ],\n },\n ],\n hooks: {\n beforeChange: [\n async ({ data, req, operation }) => {\n // Verify admin access for settings changes\n if (!req.user || req.user.collection !== 'users') {\n throw new Error('Only administrators can modify newsletter settings')\n }\n \n // If setting this config as active, deactivate all others\n if (data?.active && operation !== 'create') {\n await req.payload.update({\n collection: slug,\n where: {\n id: {\n not_equals: data.id,\n },\n },\n data: {\n active: false,\n },\n // Keep overrideAccess: true for admin operations after verification\n })\n }\n \n // For new configs, ensure only one is active\n if (operation === 'create' && data?.active) {\n const existingActive = await req.payload.find({\n collection: slug,\n where: {\n active: {\n equals: true,\n },\n },\n // Keep overrideAccess: true for admin operations\n })\n \n if (existingActive.docs.length > 0) {\n // Deactivate existing active configs\n for (const doc of existingActive.docs) {\n await req.payload.update({\n collection: slug,\n id: doc.id,\n data: {\n active: false,\n },\n // Keep overrideAccess: true for admin operations\n })\n }\n }\n }\n \n return data\n },\n ],\n afterChange: [\n async ({ doc, req }) => {\n // Reinitialize email service when settings change\n if ((req.payload as any).newsletterEmailService && doc.active) {\n try {\n // TODO: Implement email service reinitialization\n console.warn('Newsletter settings updated, reinitializing service...')\n } catch (error) {\n console.error('Failed to reinitialize email service:', error)\n }\n }\n \n return doc\n },\n ],\n },\n access: {\n read: () => true, // Settings can be read publicly for validation\n create: adminOnly(pluginConfig),\n update: adminOnly(pluginConfig),\n delete: adminOnly(pluginConfig),\n },\n timestamps: true,\n }\n}"],"names":["adminOnly","createNewsletterSettingsCollection","pluginConfig","slug","settingsSlug","labels","singular","plural","admin","useAsTitle","defaultColumns","group","description","fields","name","type","label","required","defaultValue","tabs","options","value","providers","default","condition","data","provider","i18n","locales","map","locale","toUpperCase","emailTemplates","welcome","enabled","placeholder","min","hooks","beforeChange","req","operation","user","collection","Error","active","payload","update","where","id","not_equals","existingActive","find","equals","docs","length","doc","afterChange","newsletterEmailService","console","warn","error","access","read","create","delete","timestamps"],"mappings":"AAEA,SAASA,SAAS,QAAQ,kBAAiB;AAE3C,OAAO,MAAMC,qCAAqC,CAChDC;IAEA,MAAMC,OAAOD,aAAaE,YAAY,IAAI;IAE1C,OAAO;QACLD;QACAE,QAAQ;YACNC,UAAU;YACVC,QAAQ;QACV;QACAC,OAAO;YACLC,YAAY;YACZC,gBAAgB;gBAAC;gBAAQ;gBAAY;gBAAU;aAAY;YAC3DC,OAAO;YACPC,aAAa;QACf;QACAC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNC,OAAO;gBACPC,UAAU;gBACVT,OAAO;oBACLI,aAAa;gBACf;YACF;YACA;gBACEE,MAAM;gBACNC,MAAM;gBACNC,OAAO;gBACPE,cAAc;gBACdV,OAAO;oBACLI,aAAa;gBACf;YACF;YACA;gBACEG,MAAM;gBACNI,MAAM;oBACJ;wBACEH,OAAO;wBACPH,QAAQ;4BACN;gCACEC,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPC,UAAU;gCACVG,SAAS;oCACP;wCAAEJ,OAAO;wCAAUK,OAAO;oCAAS;oCACnC;wCAAEL,OAAO;wCAA2BK,OAAO;oCAAY;iCACxD;gCACDH,cAAchB,aAAaoB,SAAS,CAACC,OAAO;gCAC5Cf,OAAO;oCACLI,aAAa;gCACf;4BACF;4BACA;gCACEE,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPR,OAAO;oCACLgB,WAAW,CAACC,OAASA,MAAMC,aAAa;gCAC1C;gCACAb,QAAQ;oCACN;wCACEC,MAAM;wCACNC,MAAM;wCACNC,OAAO;wCACPC,UAAU;wCACVT,OAAO;4CACLI,aAAa;wCACf;oCACF;oCACA;wCACEE,MAAM;wCACNC,MAAM;wCACNC,OAAO;wCACPH,QAAQ;4CACN;gDACEC,MAAM;gDACNC,MAAM;gDACNC,OAAO;gDACPC,UAAU;gDACVG,SAASlB,aAAayB,IAAI,EAAEC,SAASC,IAAIC,CAAAA,SAAW,CAAA;wDAClDd,OAAOc,OAAOC,WAAW;wDACzBV,OAAOS;oDACT,CAAA,MAAO;oDACL;wDAAEd,OAAO;wDAAMK,OAAO;oDAAK;iDAC5B;4CACH;4CACA;gDACEP,MAAM;gDACNC,MAAM;gDACNC,OAAO;4CACT;4CACA;gDACEF,MAAM;gDACNC,MAAM;gDACNC,OAAO;4CACT;yCACD;oCACH;iCACD;4BACH;4BACA;gCACEF,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPR,OAAO;oCACLgB,WAAW,CAACC,OAASA,MAAMC,aAAa;gCAC1C;gCACAb,QAAQ;oCACN;wCACEC,MAAM;wCACNC,MAAM;wCACNC,OAAO;wCACPC,UAAU;wCACVT,OAAO;4CACLI,aAAa;wCACf;oCACF;oCACA;wCACEE,MAAM;wCACNC,MAAM;wCACNC,OAAO;wCACPR,OAAO;4CACLI,aAAa;wCACf;oCACF;oCACA;wCACEE,MAAM;wCACNC,MAAM;wCACNC,OAAO;wCACPR,OAAO;4CACLI,aAAa;wCACf;oCACF;iCACD;4BACH;4BACA;gCACEE,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPC,UAAU;gCACVT,OAAO;oCACLI,aAAa;gCACf;4BACF;4BACA;gCACEE,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPC,UAAU;gCACVT,OAAO;oCACLI,aAAa;gCACf;4BACF;4BACA;gCACEE,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPR,OAAO;oCACLI,aAAa;gCACf;4BACF;yBACD;oBACH;oBACA;wBACEI,OAAO;wBACPH,QAAQ;4BACN;gCACEC,MAAM;gCACNC,MAAM;gCACNC,OAAO;gCACPH,QAAQ;oCACN;wCACEC,MAAM;wCACNC,MAAM;wCACNC,OAAO;wCACPH,QAAQ;4CACN;gDACEC,MAAM;gDACNC,MAAM;gDACNC,OAAO;gDACPE,cAAc;4CAChB;4CACA;gDACEJ,MAAM;gDACNC,MAAM;gDACNC,OAAO;gDACPE,cAAc;gDACdV,OAAO;oDACLgB,WAAW,CAACC,OAASA,MAAMO,gBAAgBC,SAASC;gDACtD;4CACF;4CACA;gDACEpB,MAAM;gDACNC,MAAM;gDACNC,OAAO;gDACPR,OAAO;oDACLgB,WAAW,CAACC,OAASA,MAAMO,gBAAgBC,SAASC;gDACtD;4CACF;yCACD;oCACH;oCACA;wCACEpB,MAAM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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { adminOnly, adminOrSelf } from '../utils/access';
|
|
1
2
|
export const createSubscribersCollection = (pluginConfig)=>{
|
|
2
3
|
const slug = pluginConfig.subscribersSlug || 'subscribers';
|
|
3
4
|
// Default fields for the subscribers collection
|
|
@@ -296,45 +297,9 @@ export const createSubscribersCollection = (pluginConfig)=>{
|
|
|
296
297
|
},
|
|
297
298
|
access: {
|
|
298
299
|
create: ()=>true,
|
|
299
|
-
read: (
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (user) {
|
|
303
|
-
return true;
|
|
304
|
-
}
|
|
305
|
-
// Magic link authenticated subscribers can read their own data
|
|
306
|
-
const subscriberId = req.user?.subscriberId;
|
|
307
|
-
if (subscriberId) {
|
|
308
|
-
return {
|
|
309
|
-
id: {
|
|
310
|
-
equals: subscriberId
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
return false;
|
|
315
|
-
},
|
|
316
|
-
update: ({ req })=>{
|
|
317
|
-
const user = req.user;
|
|
318
|
-
// Admins can update all
|
|
319
|
-
if (user?.collection === 'users') {
|
|
320
|
-
return true;
|
|
321
|
-
}
|
|
322
|
-
// Subscribers can update their own preferences
|
|
323
|
-
const subscriberId = req.user?.subscriberId;
|
|
324
|
-
if (subscriberId) {
|
|
325
|
-
return {
|
|
326
|
-
id: {
|
|
327
|
-
equals: subscriberId
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
return false;
|
|
332
|
-
},
|
|
333
|
-
delete: ({ req })=>{
|
|
334
|
-
const user = req.user;
|
|
335
|
-
// Only admins can delete
|
|
336
|
-
return Boolean(user?.collection === 'users');
|
|
337
|
-
}
|
|
300
|
+
read: adminOrSelf(pluginConfig),
|
|
301
|
+
update: adminOrSelf(pluginConfig),
|
|
302
|
+
delete: adminOnly(pluginConfig)
|
|
338
303
|
},
|
|
339
304
|
timestamps: true
|
|
340
305
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/collections/Subscribers.ts"],"sourcesContent":["import type { CollectionConfig, Field, CollectionBeforeChangeHook, CollectionAfterChangeHook, CollectionBeforeDeleteHook, Access, AccessArgs, PayloadRequest } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\n\nexport const createSubscribersCollection = (\n pluginConfig: NewsletterPluginConfig\n): CollectionConfig => {\n const slug = pluginConfig.subscribersSlug || 'subscribers'\n \n // Default fields for the subscribers collection\n const defaultFields: Field[] = [\n // Core fields\n {\n name: 'email',\n type: 'email',\n required: true,\n unique: true,\n admin: {\n description: 'Subscriber email address',\n },\n },\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Subscriber full name',\n },\n },\n {\n name: 'locale',\n type: 'select',\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n defaultValue: pluginConfig.i18n?.defaultLocale || 'en',\n admin: {\n description: 'Preferred language for communications',\n },\n },\n \n // Authentication fields (hidden from admin UI)\n {\n name: 'magicLinkToken',\n type: 'text',\n hidden: true,\n },\n {\n name: 'magicLinkTokenExpiry',\n type: 'date',\n hidden: true,\n },\n \n // Subscription status\n {\n name: 'subscriptionStatus',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Unsubscribed', value: 'unsubscribed' },\n { label: 'Pending', value: 'pending' },\n ],\n defaultValue: 'pending',\n required: true,\n admin: {\n description: 'Current subscription status',\n },\n },\n {\n name: 'unsubscribedAt',\n type: 'date',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'When the user unsubscribed',\n readOnly: true,\n },\n },\n \n // Email preferences\n {\n name: 'emailPreferences',\n type: 'group',\n fields: [\n {\n name: 'newsletter',\n type: 'checkbox',\n defaultValue: true,\n label: 'Newsletter',\n admin: {\n description: 'Receive regular newsletter updates',\n },\n },\n {\n name: 'announcements',\n type: 'checkbox',\n defaultValue: true,\n label: 'Announcements',\n admin: {\n description: 'Receive important announcements',\n },\n },\n ],\n admin: {\n description: 'Email communication preferences',\n },\n },\n \n // Source tracking\n {\n name: 'source',\n type: 'text',\n admin: {\n description: 'Where the subscriber signed up from',\n },\n },\n ]\n\n // Add UTM tracking fields if enabled\n if (pluginConfig.features?.utmTracking?.enabled) {\n const utmFields = pluginConfig.features.utmTracking.fields || [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n ]\n \n defaultFields.push({\n name: 'utmParameters',\n type: 'group',\n fields: utmFields.map(field => ({\n name: field,\n type: 'text',\n admin: {\n description: `UTM ${field} parameter`,\n },\n })),\n admin: {\n description: 'UTM tracking parameters',\n },\n })\n }\n\n // Add signup metadata\n defaultFields.push({\n name: 'signupMetadata',\n type: 'group',\n fields: [\n {\n name: 'ipAddress',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userAgent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'referrer',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'signupPage',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n ],\n admin: {\n description: 'Technical information about signup',\n },\n })\n\n // Add lead magnet field if enabled\n if (pluginConfig.features?.leadMagnets?.enabled) {\n defaultFields.push({\n name: 'leadMagnet',\n type: 'relationship',\n relationTo: pluginConfig.features.leadMagnets.collection || 'media',\n admin: {\n description: 'Lead magnet downloaded at signup',\n },\n })\n }\n\n // Allow field customization\n let fields = defaultFields\n if (pluginConfig.fields?.overrides) {\n fields = pluginConfig.fields.overrides({ defaultFields })\n }\n if (pluginConfig.fields?.additional) {\n fields = [...fields, ...pluginConfig.fields.additional]\n }\n\n const subscribersCollection: CollectionConfig = {\n slug,\n labels: {\n singular: 'Subscriber',\n plural: 'Subscribers',\n },\n admin: {\n useAsTitle: 'email',\n defaultColumns: ['email', 'name', 'subscriptionStatus', 'createdAt'],\n group: 'Newsletter',\n },\n fields,\n hooks: {\n afterChange: [\n async ({ doc, req, operation, previousDoc }) => {\n // After create logic\n if (operation === 'create') {\n // Add to email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n await emailService.addContact(doc)\n } catch (error) {\n console.error('Failed to add contact to email service:', error)\n }\n }\n\n // Send welcome email if active\n if (doc.subscriptionStatus === 'active' && emailService) {\n try {\n // TODO: Send welcome email\n } catch (error) {\n console.error('Failed to send welcome email:', error)\n }\n }\n\n // Custom after subscribe hook\n if (pluginConfig.hooks?.afterSubscribe) {\n await pluginConfig.hooks.afterSubscribe({ doc, req })\n }\n }\n \n // After update logic\n if (operation === 'update' && previousDoc) {\n // Update email service if status changed\n const emailService = (req.payload as any).newsletterEmailService\n if (\n doc.subscriptionStatus !== previousDoc.subscriptionStatus &&\n emailService\n ) {\n try {\n await emailService.updateContact(doc)\n } catch (error) {\n console.error('Failed to update contact in email service:', error)\n }\n }\n\n // Handle unsubscribe\n if (\n doc.subscriptionStatus === 'unsubscribed' &&\n previousDoc.subscriptionStatus !== 'unsubscribed'\n ) {\n // Set unsubscribed timestamp\n doc.unsubscribedAt = new Date().toISOString()\n \n // Custom after unsubscribe hook\n if (pluginConfig.hooks?.afterUnsubscribe) {\n await pluginConfig.hooks.afterUnsubscribe({ doc, req })\n }\n }\n }\n },\n ] as CollectionAfterChangeHook[],\n beforeDelete: [\n async ({ id, req }) => {\n // Remove from email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n const doc = await req.payload.findByID({\n collection: slug,\n id,\n })\n await emailService.removeContact(doc.email)\n } catch (error) {\n console.error('Failed to remove contact from email service:', error)\n }\n }\n },\n ] as CollectionBeforeDeleteHook[],\n },\n access: {\n create: () => true, // Public can subscribe\n read: (({ req }: AccessArgs) => {\n const user = (req as PayloadRequest).user\n // Admins can read all\n if (user) {\n return true\n }\n // Magic link authenticated subscribers can read their own data\n const subscriberId = (req as any).user?.subscriberId\n if (subscriberId) {\n return {\n id: {\n equals: subscriberId,\n },\n }\n }\n return false\n }) as Access,\n update: (({ req }: AccessArgs) => {\n const user = (req as PayloadRequest).user\n // Admins can update all\n if (user?.collection === 'users') {\n return true\n }\n // Subscribers can update their own preferences\n const subscriberId = (req as any).user?.subscriberId\n if (subscriberId) {\n return {\n id: {\n equals: subscriberId,\n },\n }\n }\n return false\n }) as Access,\n delete: (({ req }: AccessArgs) => {\n const user = (req as PayloadRequest).user\n // Only admins can delete\n return Boolean(user?.collection === 'users')\n }) as Access,\n },\n timestamps: true,\n }\n\n return subscribersCollection\n}"],"names":["createSubscribersCollection","pluginConfig","slug","subscribersSlug","defaultFields","name","type","required","unique","admin","description","options","i18n","locales","map","locale","label","toUpperCase","value","defaultValue","defaultLocale","hidden","condition","data","subscriptionStatus","readOnly","fields","features","utmTracking","enabled","utmFields","push","field","leadMagnets","relationTo","collection","overrides","additional","subscribersCollection","labels","singular","plural","useAsTitle","defaultColumns","group","hooks","afterChange","doc","req","operation","previousDoc","emailService","payload","newsletterEmailService","addContact","error","console","afterSubscribe","updateContact","unsubscribedAt","Date","toISOString","afterUnsubscribe","beforeDelete","id","findByID","removeContact","email","access","create","read","user","subscriberId","equals","update","delete","Boolean","timestamps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/collections/Subscribers.ts"],"sourcesContent":["import type { CollectionConfig, Field, CollectionAfterChangeHook, CollectionBeforeDeleteHook } from 'payload'\nimport type { NewsletterPluginConfig } from '../types'\nimport { adminOnly, adminOrSelf } from '../utils/access'\n\nexport const createSubscribersCollection = (\n pluginConfig: NewsletterPluginConfig\n): CollectionConfig => {\n const slug = pluginConfig.subscribersSlug || 'subscribers'\n \n // Default fields for the subscribers collection\n const defaultFields: Field[] = [\n // Core fields\n {\n name: 'email',\n type: 'email',\n required: true,\n unique: true,\n admin: {\n description: 'Subscriber email address',\n },\n },\n {\n name: 'name',\n type: 'text',\n admin: {\n description: 'Subscriber full name',\n },\n },\n {\n name: 'locale',\n type: 'select',\n options: pluginConfig.i18n?.locales?.map(locale => ({\n label: locale.toUpperCase(),\n value: locale,\n })) || [\n { label: 'EN', value: 'en' },\n ],\n defaultValue: pluginConfig.i18n?.defaultLocale || 'en',\n admin: {\n description: 'Preferred language for communications',\n },\n },\n \n // Authentication fields (hidden from admin UI)\n {\n name: 'magicLinkToken',\n type: 'text',\n hidden: true,\n },\n {\n name: 'magicLinkTokenExpiry',\n type: 'date',\n hidden: true,\n },\n \n // Subscription status\n {\n name: 'subscriptionStatus',\n type: 'select',\n options: [\n { label: 'Active', value: 'active' },\n { label: 'Unsubscribed', value: 'unsubscribed' },\n { label: 'Pending', value: 'pending' },\n ],\n defaultValue: 'pending',\n required: true,\n admin: {\n description: 'Current subscription status',\n },\n },\n {\n name: 'unsubscribedAt',\n type: 'date',\n admin: {\n condition: (data) => data?.subscriptionStatus === 'unsubscribed',\n description: 'When the user unsubscribed',\n readOnly: true,\n },\n },\n \n // Email preferences\n {\n name: 'emailPreferences',\n type: 'group',\n fields: [\n {\n name: 'newsletter',\n type: 'checkbox',\n defaultValue: true,\n label: 'Newsletter',\n admin: {\n description: 'Receive regular newsletter updates',\n },\n },\n {\n name: 'announcements',\n type: 'checkbox',\n defaultValue: true,\n label: 'Announcements',\n admin: {\n description: 'Receive important announcements',\n },\n },\n ],\n admin: {\n description: 'Email communication preferences',\n },\n },\n \n // Source tracking\n {\n name: 'source',\n type: 'text',\n admin: {\n description: 'Where the subscriber signed up from',\n },\n },\n ]\n\n // Add UTM tracking fields if enabled\n if (pluginConfig.features?.utmTracking?.enabled) {\n const utmFields = pluginConfig.features.utmTracking.fields || [\n 'source',\n 'medium',\n 'campaign',\n 'content',\n 'term',\n ]\n \n defaultFields.push({\n name: 'utmParameters',\n type: 'group',\n fields: utmFields.map(field => ({\n name: field,\n type: 'text',\n admin: {\n description: `UTM ${field} parameter`,\n },\n })),\n admin: {\n description: 'UTM tracking parameters',\n },\n })\n }\n\n // Add signup metadata\n defaultFields.push({\n name: 'signupMetadata',\n type: 'group',\n fields: [\n {\n name: 'ipAddress',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'userAgent',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'referrer',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n {\n name: 'signupPage',\n type: 'text',\n admin: {\n readOnly: true,\n },\n },\n ],\n admin: {\n description: 'Technical information about signup',\n },\n })\n\n // Add lead magnet field if enabled\n if (pluginConfig.features?.leadMagnets?.enabled) {\n defaultFields.push({\n name: 'leadMagnet',\n type: 'relationship',\n relationTo: pluginConfig.features.leadMagnets.collection || 'media',\n admin: {\n description: 'Lead magnet downloaded at signup',\n },\n })\n }\n\n // Allow field customization\n let fields = defaultFields\n if (pluginConfig.fields?.overrides) {\n fields = pluginConfig.fields.overrides({ defaultFields })\n }\n if (pluginConfig.fields?.additional) {\n fields = [...fields, ...pluginConfig.fields.additional]\n }\n\n const subscribersCollection: CollectionConfig = {\n slug,\n labels: {\n singular: 'Subscriber',\n plural: 'Subscribers',\n },\n admin: {\n useAsTitle: 'email',\n defaultColumns: ['email', 'name', 'subscriptionStatus', 'createdAt'],\n group: 'Newsletter',\n },\n fields,\n hooks: {\n afterChange: [\n async ({ doc, req, operation, previousDoc }) => {\n // After create logic\n if (operation === 'create') {\n // Add to email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n await emailService.addContact(doc)\n } catch (error) {\n console.error('Failed to add contact to email service:', error)\n }\n }\n\n // Send welcome email if active\n if (doc.subscriptionStatus === 'active' && emailService) {\n try {\n // TODO: Send welcome email\n } catch (error) {\n console.error('Failed to send welcome email:', error)\n }\n }\n\n // Custom after subscribe hook\n if (pluginConfig.hooks?.afterSubscribe) {\n await pluginConfig.hooks.afterSubscribe({ doc, req })\n }\n }\n \n // After update logic\n if (operation === 'update' && previousDoc) {\n // Update email service if status changed\n const emailService = (req.payload as any).newsletterEmailService\n if (\n doc.subscriptionStatus !== previousDoc.subscriptionStatus &&\n emailService\n ) {\n try {\n await emailService.updateContact(doc)\n } catch (error) {\n console.error('Failed to update contact in email service:', error)\n }\n }\n\n // Handle unsubscribe\n if (\n doc.subscriptionStatus === 'unsubscribed' &&\n previousDoc.subscriptionStatus !== 'unsubscribed'\n ) {\n // Set unsubscribed timestamp\n doc.unsubscribedAt = new Date().toISOString()\n \n // Custom after unsubscribe hook\n if (pluginConfig.hooks?.afterUnsubscribe) {\n await pluginConfig.hooks.afterUnsubscribe({ doc, req })\n }\n }\n }\n },\n ] as CollectionAfterChangeHook[],\n beforeDelete: [\n async ({ id, req }) => {\n // Remove from email service\n const emailService = (req.payload as any).newsletterEmailService\n if (emailService) {\n try {\n const doc = await req.payload.findByID({\n collection: slug,\n id,\n })\n await emailService.removeContact(doc.email)\n } catch (error) {\n console.error('Failed to remove contact from email service:', error)\n }\n }\n },\n ] as CollectionBeforeDeleteHook[],\n },\n access: {\n create: () => true, // Public can subscribe\n read: adminOrSelf(pluginConfig),\n update: adminOrSelf(pluginConfig),\n delete: adminOnly(pluginConfig),\n },\n timestamps: true,\n }\n\n return subscribersCollection\n}"],"names":["adminOnly","adminOrSelf","createSubscribersCollection","pluginConfig","slug","subscribersSlug","defaultFields","name","type","required","unique","admin","description","options","i18n","locales","map","locale","label","toUpperCase","value","defaultValue","defaultLocale","hidden","condition","data","subscriptionStatus","readOnly","fields","features","utmTracking","enabled","utmFields","push","field","leadMagnets","relationTo","collection","overrides","additional","subscribersCollection","labels","singular","plural","useAsTitle","defaultColumns","group","hooks","afterChange","doc","req","operation","previousDoc","emailService","payload","newsletterEmailService","addContact","error","console","afterSubscribe","updateContact","unsubscribedAt","Date","toISOString","afterUnsubscribe","beforeDelete","id","findByID","removeContact","email","access","create","read","update","delete","timestamps"],"mappings":"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"}
|
|
@@ -47,7 +47,7 @@ export const MagicLinkVerify = ({ token: propToken, onSuccess, onError, apiEndpo
|
|
|
47
47
|
} })=>{
|
|
48
48
|
const [status, setStatus] = useState('verifying');
|
|
49
49
|
const [error, setError] = useState(null);
|
|
50
|
-
const [
|
|
50
|
+
const [_sessionToken, setSessionToken] = useState(null);
|
|
51
51
|
const styles = {
|
|
52
52
|
container: {
|
|
53
53
|
...defaultStyles.container,
|