@jhits/plugin-newsletter 0.0.14 → 0.0.16
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/api/handlers/newsletters.d.ts.map +1 -1
- package/dist/api/handlers/newsletters.js +80 -24
- package/dist/api/handlers/send-newsletter.d.ts.map +1 -1
- package/dist/api/handlers/send-newsletter.js +31 -4
- package/dist/api/handlers/welcome-email.d.ts.map +1 -1
- package/dist/api/handlers/welcome-email.js +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/types/newsletter.d.ts +35 -0
- package/dist/types/newsletter.d.ts.map +1 -1
- package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -1
- package/dist/views/CanvasEditor/CanvasEditorView.js +28 -7
- package/dist/views/CanvasEditor/hooks/useNewsletterLoader.js +4 -4
- package/dist/views/NewsletterManager.d.ts.map +1 -1
- package/dist/views/NewsletterManager.js +96 -9
- package/dist/views/components/NewsletterCard.d.ts +16 -0
- package/dist/views/components/NewsletterCard.d.ts.map +1 -0
- package/dist/views/components/NewsletterCard.js +94 -0
- package/dist/views/components/NewsletterGrid.d.ts +16 -0
- package/dist/views/components/NewsletterGrid.d.ts.map +1 -0
- package/dist/views/components/NewsletterGrid.js +13 -0
- package/dist/views/components/SendNewsletterModal.js +1 -1
- package/package.json +1 -1
- package/src/api/handlers/newsletters.ts +94 -28
- package/src/api/handlers/send-newsletter.ts +33 -4
- package/src/api/handlers/welcome-email.ts +5 -2
- package/src/index.tsx +4 -1
- package/src/types/newsletter.ts +44 -0
- package/src/views/CanvasEditor/CanvasEditorView.tsx +28 -8
- package/src/views/CanvasEditor/hooks/useNewsletterLoader.ts +4 -4
- package/src/views/NewsletterManager.tsx +203 -20
- package/src/views/components/NewsletterCard.tsx +212 -0
- package/src/views/components/NewsletterGrid.tsx +48 -0
- package/src/views/components/SendNewsletterModal.tsx +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"newsletters.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/newsletters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAkC,MAAM,wBAAwB,CAAC;AAc7F,wBAAsB,eAAe,CACjC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"newsletters.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/newsletters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAkC,MAAM,wBAAwB,CAAC;AAc7F,wBAAsB,eAAe,CACjC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAsFvB;AAED,wBAAsB,cAAc,CAChC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAuEvB;AAED,wBAAsB,eAAe,CACjC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAqEvB;AAED,wBAAsB,cAAc,CAChC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CA+FvB;AAED,wBAAsB,iBAAiB,CACnC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CA8BvB"}
|
|
@@ -29,6 +29,7 @@ export async function GET_NEWSLETTERS(req, config) {
|
|
|
29
29
|
const skip = parseInt(searchParams.get('skip') || '0', 10);
|
|
30
30
|
const sortBy = searchParams.get('sortBy') || 'updatedAt';
|
|
31
31
|
const sortOrder = searchParams.get('sortOrder') || 'desc';
|
|
32
|
+
const language = searchParams.get('language') || 'en';
|
|
32
33
|
const query = {};
|
|
33
34
|
if (status) {
|
|
34
35
|
query['publication.status'] = status;
|
|
@@ -49,19 +50,36 @@ export async function GET_NEWSLETTERS(req, config) {
|
|
|
49
50
|
.limit(limit)
|
|
50
51
|
.skip(skip)
|
|
51
52
|
.toArray();
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
const primaryLanguage = 'en'; // Default primary
|
|
54
|
+
const listItems = newsletterList.map((newsletter) => {
|
|
55
|
+
const languages = newsletter.languages || {};
|
|
56
|
+
const newsletterPrimaryLang = newsletter.metadata?.lang || primaryLanguage;
|
|
57
|
+
// Get title (from subject) and subject from language-specific content
|
|
58
|
+
let title = newsletter.metadata?.subject || '';
|
|
59
|
+
if (languages[language]) {
|
|
60
|
+
title = languages[language].metadata?.subject || title;
|
|
61
|
+
}
|
|
62
|
+
else if (language !== newsletterPrimaryLang && languages[newsletterPrimaryLang]) {
|
|
63
|
+
// Fall back to primary language
|
|
64
|
+
title = languages[newsletterPrimaryLang].metadata?.subject || title;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
id: newsletter._id?.toString() || newsletter.id,
|
|
68
|
+
title: title || newsletter.title || 'Untitled',
|
|
69
|
+
slug: newsletter.slug,
|
|
70
|
+
status: newsletter.publication?.status || 'draft',
|
|
71
|
+
subject: title,
|
|
72
|
+
scheduledDate: newsletter.publication?.scheduledDate,
|
|
73
|
+
sentDate: newsletter.publication?.sentDate,
|
|
74
|
+
authorId: newsletter.publication?.authorId,
|
|
75
|
+
updatedAt: newsletter.updatedAt || newsletter.createdAt,
|
|
76
|
+
recipientCount: newsletter.recipientCount,
|
|
77
|
+
hidden: newsletter.hidden,
|
|
78
|
+
sendHistory: newsletter.sendHistory || [],
|
|
79
|
+
availableLanguages: Object.keys(languages),
|
|
80
|
+
languages,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
65
83
|
return NextResponse.json(listItems);
|
|
66
84
|
}
|
|
67
85
|
catch (error) {
|
|
@@ -75,6 +93,8 @@ export async function GET_NEWSLETTER(req, idOrSlug, config) {
|
|
|
75
93
|
if (!userId) {
|
|
76
94
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
77
95
|
}
|
|
96
|
+
const { searchParams } = new URL(req.url);
|
|
97
|
+
const language = searchParams.get('language') || 'en';
|
|
78
98
|
const dbConnection = await config.getDb();
|
|
79
99
|
const db = dbConnection.db();
|
|
80
100
|
const collectionName = config.collectionName || 'newsletters';
|
|
@@ -84,21 +104,37 @@ export async function GET_NEWSLETTER(req, idOrSlug, config) {
|
|
|
84
104
|
if (!newsletter) {
|
|
85
105
|
return NextResponse.json({ error: 'Newsletter not found' }, { status: 404 });
|
|
86
106
|
}
|
|
107
|
+
const languages = newsletter.languages || {};
|
|
108
|
+
const primaryLanguage = newsletter.metadata?.lang || 'en';
|
|
109
|
+
let blocks = newsletter.blocks || [];
|
|
110
|
+
let metadata = newsletter.metadata || {
|
|
111
|
+
subject: '',
|
|
112
|
+
previewText: '',
|
|
113
|
+
lang: 'en',
|
|
114
|
+
recipientFilter: { type: 'all' },
|
|
115
|
+
};
|
|
116
|
+
// If requested language has content, use it
|
|
117
|
+
if (languages[language]) {
|
|
118
|
+
blocks = languages[language].blocks || [];
|
|
119
|
+
metadata = { ...metadata, ...languages[language].metadata, lang: language };
|
|
120
|
+
}
|
|
121
|
+
else if (language !== primaryLanguage && languages[primaryLanguage]) {
|
|
122
|
+
// Copy from primary language if exists
|
|
123
|
+
blocks = languages[primaryLanguage].blocks || [];
|
|
124
|
+
metadata = { ...metadata, ...languages[primaryLanguage].metadata, lang: language };
|
|
125
|
+
}
|
|
87
126
|
const result = {
|
|
88
127
|
id: newsletter._id?.toString() || newsletter.id,
|
|
89
|
-
title:
|
|
128
|
+
title: metadata.subject || 'Untitled',
|
|
90
129
|
slug: newsletter.slug,
|
|
91
|
-
blocks
|
|
92
|
-
metadata
|
|
93
|
-
subject: '',
|
|
94
|
-
previewText: '',
|
|
95
|
-
lang: 'en',
|
|
96
|
-
recipientFilter: { type: 'all' },
|
|
97
|
-
},
|
|
130
|
+
blocks,
|
|
131
|
+
metadata,
|
|
98
132
|
publication: newsletter.publication || {
|
|
99
133
|
status: 'draft',
|
|
100
134
|
updatedAt: new Date().toISOString(),
|
|
101
135
|
},
|
|
136
|
+
languages,
|
|
137
|
+
sendHistory: newsletter.sendHistory,
|
|
102
138
|
createdAt: newsletter.createdAt || new Date().toISOString(),
|
|
103
139
|
updatedAt: newsletter.updatedAt || new Date().toISOString(),
|
|
104
140
|
version: newsletter.version,
|
|
@@ -175,6 +211,8 @@ export async function PUT_NEWSLETTER(req, idOrSlug, config) {
|
|
|
175
211
|
if (!userId) {
|
|
176
212
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
177
213
|
}
|
|
214
|
+
const { searchParams } = new URL(req.url);
|
|
215
|
+
const language = searchParams.get('language') || 'en';
|
|
178
216
|
const body = await req.json();
|
|
179
217
|
const { title, blocks, metadata, publication } = body;
|
|
180
218
|
const errors = [];
|
|
@@ -197,15 +235,33 @@ export async function PUT_NEWSLETTER(req, idOrSlug, config) {
|
|
|
197
235
|
if (!existing) {
|
|
198
236
|
return NextResponse.json({ error: 'Newsletter not found' }, { status: 404 });
|
|
199
237
|
}
|
|
238
|
+
// Preserve existing languages or initialize
|
|
239
|
+
const existingLanguages = existing.languages || {};
|
|
240
|
+
// Update the specific language content
|
|
241
|
+
const updatedLanguages = {
|
|
242
|
+
...existingLanguages,
|
|
243
|
+
[language]: {
|
|
244
|
+
blocks: blocks || [],
|
|
245
|
+
metadata: {
|
|
246
|
+
subject: metadata.subject.trim(),
|
|
247
|
+
previewText: metadata.previewText?.trim() || '',
|
|
248
|
+
lang: language,
|
|
249
|
+
recipientFilter: metadata.recipientFilter || { type: 'all' },
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
// Set primary language if not set
|
|
254
|
+
const primaryLanguage = existing.metadata?.lang || language;
|
|
200
255
|
const updateData = {
|
|
201
|
-
title: finalTitle,
|
|
202
|
-
blocks: blocks || [],
|
|
256
|
+
title: finalTitle, // Keep root title for backwards compatibility
|
|
257
|
+
blocks: blocks || [], // Keep blocks at root for backwards compatibility
|
|
203
258
|
metadata: {
|
|
204
259
|
subject: metadata.subject.trim(),
|
|
205
260
|
previewText: metadata.previewText?.trim() || '',
|
|
206
|
-
lang:
|
|
261
|
+
lang: primaryLanguage,
|
|
207
262
|
recipientFilter: metadata.recipientFilter || { type: 'all' },
|
|
208
263
|
},
|
|
264
|
+
languages: updatedLanguages,
|
|
209
265
|
publication: {
|
|
210
266
|
...existing.publication,
|
|
211
267
|
status: publication?.status || existing.publication?.status || 'draft',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-newsletter.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/send-newsletter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AA4C7D,wBAAsB,oBAAoB,CACtC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"send-newsletter.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/send-newsletter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AA4C7D,wBAAsB,oBAAoB,CACtC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAwNvB;AAED,wBAAsB,uBAAuB,CACzC,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAuCvB"}
|
|
@@ -47,8 +47,21 @@ export async function POST_SEND_NEWSLETTER(req, idOrSlug, config) {
|
|
|
47
47
|
if (!newsletter) {
|
|
48
48
|
return NextResponse.json({ error: 'Newsletter not found' }, { status: 404 });
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
const
|
|
50
|
+
// Get language-specific content if available
|
|
51
|
+
const languages = newsletter.languages || {};
|
|
52
|
+
const primaryLanguage = newsletter.metadata?.lang || 'en';
|
|
53
|
+
let blocks = newsletter.blocks || [];
|
|
54
|
+
let metadata = newsletter.metadata || {};
|
|
55
|
+
// If the requested language has content, use it
|
|
56
|
+
if (language && languages[language]) {
|
|
57
|
+
blocks = languages[language].blocks || [];
|
|
58
|
+
metadata = { ...metadata, ...languages[language].metadata };
|
|
59
|
+
}
|
|
60
|
+
else if (language !== primaryLanguage && languages[primaryLanguage]) {
|
|
61
|
+
// Fall back to primary language content
|
|
62
|
+
blocks = languages[primaryLanguage].blocks || [];
|
|
63
|
+
metadata = { ...metadata, ...languages[primaryLanguage].metadata };
|
|
64
|
+
}
|
|
52
65
|
if (!blocks || blocks.length === 0) {
|
|
53
66
|
return NextResponse.json({ error: 'Newsletter has no content' }, { status: 400 });
|
|
54
67
|
}
|
|
@@ -102,11 +115,16 @@ export async function POST_SEND_NEWSLETTER(req, idOrSlug, config) {
|
|
|
102
115
|
recipientCount = 1;
|
|
103
116
|
}
|
|
104
117
|
else {
|
|
105
|
-
|
|
118
|
+
// Filter subscribers by the selected language
|
|
119
|
+
const subscriberFilter = { status: 'active' };
|
|
120
|
+
if (language) {
|
|
121
|
+
subscriberFilter.language = language;
|
|
122
|
+
}
|
|
123
|
+
const subscriberList = await subscribers.find(subscriberFilter).toArray();
|
|
106
124
|
recipientEmails = subscriberList.map((s) => s.email);
|
|
107
125
|
recipientCount = recipientEmails.length;
|
|
108
126
|
if (recipientCount === 0) {
|
|
109
|
-
return NextResponse.json({ error:
|
|
127
|
+
return NextResponse.json({ error: `No active subscribers found for language: ${language?.toUpperCase() || 'en'}` }, { status: 400 });
|
|
110
128
|
}
|
|
111
129
|
}
|
|
112
130
|
const subject = metadata.subject || 'Newsletter';
|
|
@@ -147,12 +165,21 @@ export async function POST_SEND_NEWSLETTER(req, idOrSlug, config) {
|
|
|
147
165
|
}
|
|
148
166
|
}
|
|
149
167
|
if (!isTest && successCount > 0) {
|
|
168
|
+
const sendHistoryEntry = {
|
|
169
|
+
language,
|
|
170
|
+
sentAt: new Date().toISOString(),
|
|
171
|
+
recipientCount: successCount,
|
|
172
|
+
authorId: userId,
|
|
173
|
+
};
|
|
150
174
|
await newsletters.updateOne(filter, {
|
|
151
175
|
$set: {
|
|
152
176
|
'publication.status': 'sent',
|
|
153
177
|
'publication.sentDate': new Date().toISOString(),
|
|
154
178
|
'publication.recipientCount': successCount,
|
|
155
179
|
updatedAt: new Date().toISOString(),
|
|
180
|
+
},
|
|
181
|
+
$push: {
|
|
182
|
+
sendHistory: sendHistoryEntry,
|
|
156
183
|
}
|
|
157
184
|
});
|
|
158
185
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"welcome-email.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/welcome-email.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAajF,wBAAsB,wBAAwB,CAC1C,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED,wBAAsB,iBAAiB,CACnC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"welcome-email.d.ts","sourceRoot":"","sources":["../../../src/api/handlers/welcome-email.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAajF,wBAAsB,wBAAwB,CAC1C,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED,wBAAsB,iBAAiB,CACnC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAgEvB;AAED,wBAAsB,kBAAkB,CACpC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAyDvB;AAED,wBAAsB,yBAAyB,CAC3C,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,mBAAmB,EAC3B,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAAC,QAAQ,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAc1D"}
|
|
@@ -62,7 +62,7 @@ export async function GET_WELCOME_EMAIL(req, config) {
|
|
|
62
62
|
title: 'Welcome Email',
|
|
63
63
|
language,
|
|
64
64
|
blocks: primaryContent.blocks,
|
|
65
|
-
metadata: primaryContent.metadata,
|
|
65
|
+
metadata: { ...primaryContent.metadata, lang: language },
|
|
66
66
|
languages,
|
|
67
67
|
isCopy: true,
|
|
68
68
|
copyFrom: primaryLanguage,
|
|
@@ -74,7 +74,10 @@ export async function GET_WELCOME_EMAIL(req, config) {
|
|
|
74
74
|
title: 'Welcome Email',
|
|
75
75
|
language,
|
|
76
76
|
blocks: languages[language]?.blocks || primaryContent.blocks,
|
|
77
|
-
metadata:
|
|
77
|
+
metadata: {
|
|
78
|
+
...(languages[language]?.metadata || primaryContent.metadata),
|
|
79
|
+
lang: language
|
|
80
|
+
},
|
|
78
81
|
languages,
|
|
79
82
|
isCopy: false,
|
|
80
83
|
});
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD;;;GAGG;AACH,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,yGAAyG;IACzG,YAAY,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACvC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,iDAAiD;QACjD,KAAK,EAAE,MAAM,CAAC;QACd,gDAAgD;QAChD,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACL;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,KAAK,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAOtD;;;GAGG;AACH,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,yGAAyG;IACzG,YAAY,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACvC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,iDAAiD;QACjD,KAAK,EAAE,MAAM,CAAC;QACd,gDAAgD;QAChD,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACL;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,KAAK,EAAE,WAAW,2CAiR1D;AAGD,OAAO,EAAE,gBAAgB,IAAI,KAAK,EAAE,CAAC;AAGrC,YAAY,EACR,KAAK,EACL,mBAAmB,EACnB,qBAAqB,EACrB,wBAAwB,EACxB,cAAc,EACd,iBAAiB,EACjB,eAAe,GAClB,MAAM,eAAe,CAAC;AAGvB,YAAY,EACR,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,GAC1B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,QAAQ,CAAC;AAC9C,YAAY,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAGrD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClE,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGpF,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -130,10 +130,12 @@ export default function NewsletterPlugin(props) {
|
|
|
130
130
|
apiData.metadata = apiData.metadata || {};
|
|
131
131
|
apiData.metadata.lang = extraData.language;
|
|
132
132
|
}
|
|
133
|
+
// Build URL with language param if provided
|
|
134
|
+
const langParam = extraData?.language ? `?language=${extraData.language}` : '';
|
|
133
135
|
// If we have an id, try to update first
|
|
134
136
|
if (originalId) {
|
|
135
137
|
console.log('[NewsletterPlugin] Attempting to update newsletter with id:', originalId);
|
|
136
|
-
const updateResponse = await fetch(`/api/plugin-newsletter/newsletters/${originalId}`, {
|
|
138
|
+
const updateResponse = await fetch(`/api/plugin-newsletter/newsletters/${originalId}${langParam}`, {
|
|
137
139
|
method: 'PUT',
|
|
138
140
|
headers: { 'Content-Type': 'application/json' },
|
|
139
141
|
credentials: 'include',
|
|
@@ -38,6 +38,21 @@ export interface NewsletterPublicationData {
|
|
|
38
38
|
authorId?: string;
|
|
39
39
|
/** Last modified date */
|
|
40
40
|
updatedAt?: string;
|
|
41
|
+
/** Recipient count for last send */
|
|
42
|
+
recipientCount?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Send history entry for tracking sends per language
|
|
46
|
+
*/
|
|
47
|
+
export interface SendHistoryEntry {
|
|
48
|
+
/** Language code sent to */
|
|
49
|
+
language: string;
|
|
50
|
+
/** When this was sent */
|
|
51
|
+
sentAt: string;
|
|
52
|
+
/** Number of recipients */
|
|
53
|
+
recipientCount: number;
|
|
54
|
+
/** Who sent it (author ID) */
|
|
55
|
+
authorId?: string;
|
|
41
56
|
}
|
|
42
57
|
/**
|
|
43
58
|
* Newsletter Metadata
|
|
@@ -55,6 +70,19 @@ export interface NewsletterMetadata {
|
|
|
55
70
|
value?: string;
|
|
56
71
|
};
|
|
57
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Newsletter language content (blocks + metadata per language)
|
|
75
|
+
*/
|
|
76
|
+
export interface NewsletterLanguageContent {
|
|
77
|
+
blocks: Block[];
|
|
78
|
+
metadata: NewsletterMetadata;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Languages object storing content per language
|
|
82
|
+
*/
|
|
83
|
+
export interface NewsletterLanguages {
|
|
84
|
+
[key: string]: NewsletterLanguageContent;
|
|
85
|
+
}
|
|
58
86
|
/**
|
|
59
87
|
* Complete Newsletter Structure
|
|
60
88
|
* This is the headless JSON structure stored in the database
|
|
@@ -70,6 +98,10 @@ export interface Newsletter {
|
|
|
70
98
|
blocks: Block[];
|
|
71
99
|
/** Publication data */
|
|
72
100
|
publication: NewsletterPublicationData;
|
|
101
|
+
/** Send history for tracking multiple sends per language */
|
|
102
|
+
sendHistory?: SendHistoryEntry[];
|
|
103
|
+
/** Content per language (for multi-language newsletters) */
|
|
104
|
+
languages?: NewsletterLanguages;
|
|
73
105
|
/** Additional metadata */
|
|
74
106
|
metadata: NewsletterMetadata;
|
|
75
107
|
/** Creation timestamp */
|
|
@@ -95,6 +127,9 @@ export interface NewsletterListItem {
|
|
|
95
127
|
updatedAt: string;
|
|
96
128
|
recipientCount?: number;
|
|
97
129
|
hidden?: boolean;
|
|
130
|
+
sendHistory?: SendHistoryEntry[];
|
|
131
|
+
availableLanguages?: string[];
|
|
132
|
+
languages?: NewsletterLanguages;
|
|
98
133
|
}
|
|
99
134
|
/**
|
|
100
135
|
* Newsletter Filter Options
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"newsletter.d.ts","sourceRoot":"","sources":["../../src/types/newsletter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,MAAM,WAAW,UAAU;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,IAAI,GAAG,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,QAAQ,GAAG,cAAc,CAAC;CACtC;AAED,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG;YACX,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,EAAE,MAAM,CAAC;SACnB,CAAC;KACL,CAAC;IACF,SAAS,CAAC,EAAE,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,UAAU,CAAC;AAE3E;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACtC,yBAAyB;IACzB,MAAM,EAAE,gBAAgB,CAAC;IAEzB,uCAAuC;IACvC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,gBAAgB;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,yBAAyB;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"newsletter.d.ts","sourceRoot":"","sources":["../../src/types/newsletter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CanvasEditorView.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/CanvasEditorView.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,qBAAqB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"CanvasEditorView.d.ts","sourceRoot":"","sources":["../../../src/views/CanvasEditor/CanvasEditorView.tsx"],"names":[],"mappings":"AAeA,MAAM,WAAW,qBAAqB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE;QACf,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,oDAAoD;IACpD,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,gBAAgB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,EAAE,qBAAqB,2CA4U1J"}
|
|
@@ -25,12 +25,23 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
25
25
|
const [currentLanguage, setCurrentLanguage] = useState(locale || 'en');
|
|
26
26
|
// Get registered blocks
|
|
27
27
|
const registeredBlocks = useRegisteredBlocks();
|
|
28
|
-
// Newsletter loading -
|
|
28
|
+
// Newsletter loading - wait for language settings to be loaded first
|
|
29
29
|
const { isLoadingNewsletter } = useNewsletterLoader(newsletterId, state.newsletterId, (newsletter) => {
|
|
30
30
|
helpers.loadNewsletter(newsletter);
|
|
31
|
-
// Set current language from loaded newsletter metadata
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
// Set current language from loaded newsletter (check both metadata.lang and top-level language)
|
|
32
|
+
const loadedLanguage = newsletter.metadata?.lang || newsletter.language;
|
|
33
|
+
if (loadedLanguage) {
|
|
34
|
+
setCurrentLanguage(loadedLanguage);
|
|
35
|
+
}
|
|
36
|
+
// Update available languages from newsletter's languages object (for regular newsletters)
|
|
37
|
+
if (!isWelcomeEmail && newsletter.languages && Object.keys(newsletter.languages).length > 0) {
|
|
38
|
+
const langs = Object.keys(newsletter.languages);
|
|
39
|
+
setAvailableLanguages(langs);
|
|
40
|
+
}
|
|
41
|
+
// For welcome emails, also update available languages
|
|
42
|
+
if (isWelcomeEmail && newsletter.languages && Object.keys(newsletter.languages).length > 0) {
|
|
43
|
+
const langs = Object.keys(newsletter.languages);
|
|
44
|
+
setAvailableLanguages(langs);
|
|
34
45
|
}
|
|
35
46
|
setTimeout(() => {
|
|
36
47
|
dispatch({ type: 'MARK_CLEAN' });
|
|
@@ -75,8 +86,17 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
75
86
|
}
|
|
76
87
|
setCurrentLanguage(newLanguage);
|
|
77
88
|
// Reload with new language
|
|
78
|
-
|
|
79
|
-
if (
|
|
89
|
+
let response;
|
|
90
|
+
if (isWelcomeEmail) {
|
|
91
|
+
response = await fetch(`/api/plugin-newsletter/welcome-email?language=${newLanguage}`);
|
|
92
|
+
}
|
|
93
|
+
else if (newsletterId) {
|
|
94
|
+
response = await fetch(`/api/plugin-newsletter/newsletters/${newsletterId}?language=${newLanguage}`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (response && response.ok) {
|
|
80
100
|
const newsletter = await response.json();
|
|
81
101
|
helpers.loadNewsletter(newsletter);
|
|
82
102
|
dispatch({ type: 'MARK_CLEAN' });
|
|
@@ -170,7 +190,8 @@ export function CanvasEditorView({ newsletterId, darkMode, backgroundColors: pro
|
|
|
170
190
|
setIsSaving(true);
|
|
171
191
|
setSaveError(null);
|
|
172
192
|
try {
|
|
173
|
-
|
|
193
|
+
// Always pass language for saving (both welcome email and regular newsletters)
|
|
194
|
+
await helpers.save({ language: currentLanguage });
|
|
174
195
|
setIsSaving(false);
|
|
175
196
|
}
|
|
176
197
|
catch (error) {
|
|
@@ -7,13 +7,12 @@ export function useNewsletterLoader(newsletterId, currentNewsletterId, loadNewsl
|
|
|
7
7
|
if (hasLoadedRef.current) {
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
|
-
//
|
|
11
|
-
if (
|
|
10
|
+
// Wait until language is provided (for both welcome emails and regular newsletters)
|
|
11
|
+
if (!language) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
// Skip if we have a regular newsletter id but no id yet, or if this is welcome email mode
|
|
15
15
|
if (isWelcomeEmail) {
|
|
16
|
-
// Load welcome email with language
|
|
17
16
|
// Load welcome email with language
|
|
18
17
|
const loadWelcomeEmail = async () => {
|
|
19
18
|
try {
|
|
@@ -41,7 +40,8 @@ export function useNewsletterLoader(newsletterId, currentNewsletterId, loadNewsl
|
|
|
41
40
|
const loadNewsletterData = async () => {
|
|
42
41
|
try {
|
|
43
42
|
setIsLoadingNewsletter(true);
|
|
44
|
-
const
|
|
43
|
+
const langParam = language ? `?language=${language}` : '';
|
|
44
|
+
const response = await fetch(`/api/plugin-newsletter/newsletters/${newsletterId}${langParam}`);
|
|
45
45
|
if (!response.ok) {
|
|
46
46
|
throw new Error('Failed to load newsletter');
|
|
47
47
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NewsletterManager.d.ts","sourceRoot":"","sources":["../../src/views/NewsletterManager.tsx"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"NewsletterManager.d.ts","sourceRoot":"","sources":["../../src/views/NewsletterManager.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,WAAW,0BAA0B;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAClB;AAiBD,wBAAgB,qBAAqB,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,0BAA0B,2CAqnBnF"}
|