@flowselections/actie-mail-kwekers-erp-mathot 1.0.20 → 1.0.21
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-lib/components/settings/AfzenderSettingsCard.d.ts +2 -0
- package/dist-lib/components/settings/AfzenderSettingsCard.d.ts.map +1 -0
- package/dist-lib/components/settings/AfzenderSettingsCard.js +30 -0
- package/dist-lib/integrations/supabase/auth-middleware.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.d.ts.map +1 -1
- package/dist-lib/integrations/supabase/client.server.d.ts.map +1 -1
- package/dist-lib/lib/branding.functions.d.ts +3 -9
- package/dist-lib/lib/branding.functions.d.ts.map +1 -1
- package/dist-lib/lib/campaigns.functions.d.ts.map +1 -1
- package/dist-lib/lib/campaigns.functions.js +76 -66
- package/dist-lib/lib/stats.functions.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -214,18 +214,18 @@ export const sendCampaign = createServerFn({ method: "POST" })
|
|
|
214
214
|
const stickerLine = p.sticker_cost && Number(p.sticker_cost) > 0
|
|
215
215
|
? `<div style="margin-top:12px;background:#eff6ff;border-left:4px solid #3b82f6;padding:10px 12px;border-radius:4px;font-size:14px;color:#1e3a8a;">📋 <strong>Eigen sticker opdrukken:</strong> ${fmtEuro(Number(p.sticker_cost))} per stuk</div>`
|
|
216
216
|
: "";
|
|
217
|
-
return `<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="border:1px solid #e5e7eb;border-radius:8px;margin:0 0 16px 0;background:#fff;">
|
|
218
|
-
<tr>
|
|
219
|
-
<td style="padding:14px;vertical-align:top;width:112px;">${imageCell}</td>
|
|
220
|
-
<td style="padding:14px 14px 14px 0;vertical-align:top;">
|
|
221
|
-
<div style="font-size:16px;font-weight:700;color:#111;line-height:1.3;">${escapeHtml(p.product_name)}</div>
|
|
222
|
-
${p.plants_per_crate ? `<div style="font-size:13px;color:#6b7280;margin-top:2px;">${p.plants_per_crate} planten per fust</div>` : ""}
|
|
223
|
-
${p.barcode ? `<div style="font-size:13px;color:#6b7280;margin-top:2px;">Barcode: ${escapeHtml(String(p.barcode))}</div>` : ""}
|
|
224
|
-
${normal > 0 ? `<div style="font-size:13px;color:#9ca3af;text-decoration:line-through;margin-top:6px;">Origineel: ${fmtEuro(normal)}</div>` : ""}
|
|
225
|
-
<div style="margin-top:6px;">${tierChips}</div>
|
|
226
|
-
</td>
|
|
227
|
-
</tr>
|
|
228
|
-
${stickerLine ? `<tr><td colspan="2" style="padding:0 14px 14px 14px;">${stickerLine}</td></tr>` : ""}
|
|
217
|
+
return `<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="border:1px solid #e5e7eb;border-radius:8px;margin:0 0 16px 0;background:#fff;">
|
|
218
|
+
<tr>
|
|
219
|
+
<td style="padding:14px;vertical-align:top;width:112px;">${imageCell}</td>
|
|
220
|
+
<td style="padding:14px 14px 14px 0;vertical-align:top;">
|
|
221
|
+
<div style="font-size:16px;font-weight:700;color:#111;line-height:1.3;">${escapeHtml(p.product_name)}</div>
|
|
222
|
+
${p.plants_per_crate ? `<div style="font-size:13px;color:#6b7280;margin-top:2px;">${p.plants_per_crate} planten per fust</div>` : ""}
|
|
223
|
+
${p.barcode ? `<div style="font-size:13px;color:#6b7280;margin-top:2px;">Barcode: ${escapeHtml(String(p.barcode))}</div>` : ""}
|
|
224
|
+
${normal > 0 ? `<div style="font-size:13px;color:#9ca3af;text-decoration:line-through;margin-top:6px;">Origineel: ${fmtEuro(normal)}</div>` : ""}
|
|
225
|
+
<div style="margin-top:6px;">${tierChips}</div>
|
|
226
|
+
</td>
|
|
227
|
+
</tr>
|
|
228
|
+
${stickerLine ? `<tr><td colspan="2" style="padding:0 14px 14px 14px;">${stickerLine}</td></tr>` : ""}
|
|
229
229
|
</table>`;
|
|
230
230
|
};
|
|
231
231
|
const productsHtml = (products ?? []).map(renderProduct).join("");
|
|
@@ -234,43 +234,43 @@ export const sendCampaign = createServerFn({ method: "POST" })
|
|
|
234
234
|
const failed = [];
|
|
235
235
|
for (const r of recipients ?? []) {
|
|
236
236
|
const actionUrl = `${origin}/actie/${r.link_code}`;
|
|
237
|
-
const html = `<!doctype html><html><body style="margin:0;padding:0;font-family:Arial,Helvetica,sans-serif;background:#f3f4f6;">
|
|
238
|
-
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#f3f4f6;padding:24px 0;">
|
|
239
|
-
<tr><td align="center">
|
|
240
|
-
<table role="presentation" cellpadding="0" cellspacing="0" width="600" style="max-width:600px;width:100%;background:#ffffff;border-radius:12px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
|
|
241
|
-
<tr>
|
|
242
|
-
<td bgcolor="${brand.primary}" style="background-color:${brand.primary};background-image:linear-gradient(135deg,${brand.primary},${brand.primaryDark});padding:28px 24px;text-align:center;">
|
|
243
|
-
${brand.logoUrl ? `<div style="margin:0 0 12px 0;"><img src="${escapeHtml(brand.logoUrl)}" alt="${escapeHtml(brand.brandName ?? "")}" height="40" style="display:inline-block;height:40px;max-width:220px;width:auto;border:0;" /></div>` : ""}
|
|
244
|
-
<div style="font-size:24px;font-weight:800;color:#ffffff;letter-spacing:-0.01em;">${escapeHtml(campaign.subject)}</div>
|
|
245
|
-
</td>
|
|
246
|
-
</tr>
|
|
247
|
-
<tr>
|
|
248
|
-
<td style="padding:24px;background:#f9fafb;">
|
|
249
|
-
<p style="margin:0 0 12px 0;color:#111;font-size:15px;">Beste ${escapeHtml(r.recipient_name)},</p>
|
|
250
|
-
${campaign.intro_message ? `<p style="margin:0 0 20px 0;color:#374151;font-size:15px;white-space:pre-line;line-height:1.5;">${escapeHtml(campaign.intro_message)}</p>` : `<p style="margin:0 0 20px 0;color:#374151;font-size:15px;">Wij hebben een mooie aanbieding voor u!</p>`}
|
|
251
|
-
|
|
252
|
-
${productsHtml ? `<h2 style="margin:24px 0 8px 0;color:${brand.primaryText};font-size:22px;border-bottom:2px solid ${brand.primary};padding-bottom:6px;">Aanbiedingen</h2>${productsHtml}` : ""}
|
|
253
|
-
|
|
254
|
-
<div style="margin:16px 0;background:#fef3c7;border-left:4px solid #f59e0b;padding:12px 14px;border-radius:4px;color:#92400e;font-size:14px;">
|
|
255
|
-
⏰ <strong>Actie geldig zolang de voorraad strekt!</strong>
|
|
256
|
-
</div>
|
|
257
|
-
|
|
258
|
-
<p style="margin:28px 0;text-align:center;">
|
|
259
|
-
<a href="${actionUrl}" style="background:${brand.button};color:${brand.buttonText};padding:14px 28px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:700;font-size:16px;">🛒 Direct Bestellen</a>
|
|
260
|
-
</p>
|
|
261
|
-
|
|
262
|
-
<p style="color:#6b7280;font-size:12px;text-align:center;margin:16px 0 0 0;">Of <a href="${actionUrl}" style="color:${brand.primaryText};text-decoration:underline;">open deze link</a>.</p>
|
|
263
|
-
</td>
|
|
264
|
-
</tr>
|
|
265
|
-
<tr>
|
|
266
|
-
<td style="padding:18px 24px;background:#ffffff;border-top:1px solid #e5e7eb;color:#6b7280;font-size:12px;text-align:center;">
|
|
267
|
-
Met vriendelijke groet,<br/><strong>${escapeHtml(campaign.from_name ?? brand.brandName ?? "")}</strong>
|
|
268
|
-
</td>
|
|
269
|
-
</tr>
|
|
270
|
-
</table>
|
|
271
|
-
</td></tr>
|
|
272
|
-
</table>
|
|
273
|
-
${trackingEnabled ? `<img src="${origin}/api/public/pixel/${r.link_code}.gif" width="1" height="1" alt="" style="display:block;border:0;width:1px;height:1px;" />` : ""}
|
|
237
|
+
const html = `<!doctype html><html><body style="margin:0;padding:0;font-family:Arial,Helvetica,sans-serif;background:#f3f4f6;">
|
|
238
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#f3f4f6;padding:24px 0;">
|
|
239
|
+
<tr><td align="center">
|
|
240
|
+
<table role="presentation" cellpadding="0" cellspacing="0" width="600" style="max-width:600px;width:100%;background:#ffffff;border-radius:12px;overflow:hidden;box-shadow:0 1px 3px rgba(0,0,0,0.06);">
|
|
241
|
+
<tr>
|
|
242
|
+
<td bgcolor="${brand.primary}" style="background-color:${brand.primary};background-image:linear-gradient(135deg,${brand.primary},${brand.primaryDark});padding:28px 24px;text-align:center;">
|
|
243
|
+
${brand.logoUrl ? `<div style="margin:0 0 12px 0;"><img src="${escapeHtml(brand.logoUrl)}" alt="${escapeHtml(brand.brandName ?? "")}" height="40" style="display:inline-block;height:40px;max-width:220px;width:auto;border:0;" /></div>` : ""}
|
|
244
|
+
<div style="font-size:24px;font-weight:800;color:#ffffff;letter-spacing:-0.01em;">${escapeHtml(campaign.subject)}</div>
|
|
245
|
+
</td>
|
|
246
|
+
</tr>
|
|
247
|
+
<tr>
|
|
248
|
+
<td style="padding:24px;background:#f9fafb;">
|
|
249
|
+
<p style="margin:0 0 12px 0;color:#111;font-size:15px;">Beste ${escapeHtml(r.recipient_name)},</p>
|
|
250
|
+
${campaign.intro_message ? `<p style="margin:0 0 20px 0;color:#374151;font-size:15px;white-space:pre-line;line-height:1.5;">${escapeHtml(campaign.intro_message)}</p>` : `<p style="margin:0 0 20px 0;color:#374151;font-size:15px;">Wij hebben een mooie aanbieding voor u!</p>`}
|
|
251
|
+
|
|
252
|
+
${productsHtml ? `<h2 style="margin:24px 0 8px 0;color:${brand.primaryText};font-size:22px;border-bottom:2px solid ${brand.primary};padding-bottom:6px;">Aanbiedingen</h2>${productsHtml}` : ""}
|
|
253
|
+
|
|
254
|
+
<div style="margin:16px 0;background:#fef3c7;border-left:4px solid #f59e0b;padding:12px 14px;border-radius:4px;color:#92400e;font-size:14px;">
|
|
255
|
+
⏰ <strong>Actie geldig zolang de voorraad strekt!</strong>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
<p style="margin:28px 0;text-align:center;">
|
|
259
|
+
<a href="${actionUrl}" style="background:${brand.button};color:${brand.buttonText};padding:14px 28px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:700;font-size:16px;">🛒 Direct Bestellen</a>
|
|
260
|
+
</p>
|
|
261
|
+
|
|
262
|
+
<p style="color:#6b7280;font-size:12px;text-align:center;margin:16px 0 0 0;">Of <a href="${actionUrl}" style="color:${brand.primaryText};text-decoration:underline;">open deze link</a>.</p>
|
|
263
|
+
</td>
|
|
264
|
+
</tr>
|
|
265
|
+
<tr>
|
|
266
|
+
<td style="padding:18px 24px;background:#ffffff;border-top:1px solid #e5e7eb;color:#6b7280;font-size:12px;text-align:center;">
|
|
267
|
+
Met vriendelijke groet,<br/><strong>${escapeHtml(campaign.from_name ?? brand.brandName ?? "")}</strong>
|
|
268
|
+
</td>
|
|
269
|
+
</tr>
|
|
270
|
+
</table>
|
|
271
|
+
</td></tr>
|
|
272
|
+
</table>
|
|
273
|
+
${trackingEnabled ? `<img src="${origin}/api/public/pixel/${r.link_code}.gif" width="1" height="1" alt="" style="display:block;border:0;width:1px;height:1px;" />` : ""}
|
|
274
274
|
</body></html>`;
|
|
275
275
|
try {
|
|
276
276
|
const { error: insErr } = await supabase
|
|
@@ -320,25 +320,35 @@ export const sendCampaign = createServerFn({ method: "POST" })
|
|
|
320
320
|
.update({ status: "sent", sent_at: now })
|
|
321
321
|
.eq("id", data.campaignId);
|
|
322
322
|
}
|
|
323
|
-
// Trigger de outbox-dispatcher onmiddellijk, zodat we niet
|
|
324
|
-
// tot de cron (elke minuut) draait.
|
|
325
|
-
//
|
|
323
|
+
// Trigger de outbox-dispatcher van de EIGEN shell onmiddellijk, zodat we niet
|
|
324
|
+
// hoeven te wachten tot de cron (elke minuut) draait. De cron blijft het vangnet:
|
|
325
|
+
// faalt deze aanroep, dan worden de mails alsnog verstuurd — maar nooit stil,
|
|
326
|
+
// een mislukking wordt altijd gelogd.
|
|
326
327
|
if (sentIds.length > 0) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
328
|
+
const dispatchBase = (process.env.PUBLIC_BASE_URL ?? origin ?? "").replace(/\/$/, "");
|
|
329
|
+
if (!dispatchBase) {
|
|
330
|
+
console.warn("[aanbiedingsmailtje] Outbox-dispatcher overgeslagen: geen basis-URL bekend " +
|
|
331
|
+
"(stel PUBLIC_BASE_URL in). De cron verwerkt de wachtrij binnen een minuut.");
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
const dispatchUrl = `${dispatchBase}/api/public/email-auth/outbox-process`;
|
|
335
|
+
try {
|
|
336
|
+
const res = await fetch(dispatchUrl, {
|
|
337
|
+
method: "POST",
|
|
338
|
+
headers: { "Content-Type": "application/json" },
|
|
339
|
+
body: "{}",
|
|
340
|
+
});
|
|
341
|
+
if (!res.ok) {
|
|
342
|
+
const detail = await res.text().catch(() => "");
|
|
343
|
+
console.warn(`[aanbiedingsmailtje] Outbox-dispatcher gaf ${res.status} ${res.statusText} ` +
|
|
344
|
+
`voor ${dispatchUrl}: ${detail.slice(0, 300)}. De cron verwerkt de wachtrij als vangnet.`);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
catch (e) {
|
|
348
|
+
console.warn(`[aanbiedingsmailtje] Outbox-dispatcher onbereikbaar op ${dispatchUrl}: ` +
|
|
349
|
+
`${String(e?.message ?? e)}. De cron verwerkt de wachtrij als vangnet.`);
|
|
350
|
+
}
|
|
340
351
|
}
|
|
341
|
-
catch { /* noop */ }
|
|
342
352
|
}
|
|
343
353
|
return { sent: sentIds.length, failed: failed.length, errors: failed.slice(0, 5) };
|
|
344
354
|
});
|