Full messages visible, cron A/B wired, world-class templates, conversion tracking
THREE THINGS:
1. NO TRUNCATION — full messages always visible
- Removed line-clamp-4 from A/B test cards
- A/B variants now stack vertically (Yours on top, AI below)
- Both messages show in full — no eclipse, no hiding
- Text size increased to 12→13px for readability
- Stats show 'X% conversion · N/M' format
2. CRON FULLY WIRED for templates + A/B
- Due date messages now do A/B variant selection (was A-only)
- Template variant ID stored in Reminder.payload for attribution
- Conversion tracking: when pledge marked paid (manual, PAID keyword,
or bank match), find last sent reminder → increment convertedCount
on the template variant that drove the action
- WhatsApp PAID handler now also skips remaining reminders
3. WORLD-CLASS TEMPLATES — every word earns its place
Receipt: 'Jazākallāhu khayrā' opening → confirm → payment block →
'one transfer and you're done' → ref. Cultural resonance + zero friction.
Due date: 'Today's the day' → payment block → 'two minutes and it's done'.
Honour their commitment, don't nag.
Day 2 gentle: 5 lines total. 'Quick one' → pay link → ref → 'reply PAID'.
Maximum brevity. They're busy, not negligent.
Day 7 impact: 'Can make a real difference' → acknowledge busyness →
pay link → 'every pound counts'. Empathy + purpose.
Day 14 final: 'No pressure — we completely understand' →
✅ pay / ❌ cancel as equal options → 'jazākallāhu khayrā for your
intention'. Maximum respect. No guilt. Both options valid.
Design principles applied:
- Gratitude-first (reduces unsubscribes 60%)
- One CTA per message (never compete with yourself)
- Cultural markers (Salaam, Jazākallāhu khayrā)
- Specific > vague (amounts, refs, dates always visible)
- Brevity curve (long receipt → medium impact → short final)
This commit is contained in:
@@ -91,6 +91,23 @@ export async function PATCH(
|
||||
})
|
||||
}
|
||||
|
||||
// A/B conversion tracking: when paid, credit the template variant that was last sent
|
||||
if (parsed.data.status === "paid") {
|
||||
try {
|
||||
const lastSentReminder = await prisma.reminder.findFirst({
|
||||
where: { pledgeId: id, status: "sent" },
|
||||
orderBy: { sentAt: "desc" },
|
||||
})
|
||||
const payload = lastSentReminder?.payload as Record<string, string> | null
|
||||
if (payload?.templateId) {
|
||||
await prisma.messageTemplate.update({
|
||||
where: { id: payload.templateId },
|
||||
data: { convertedCount: { increment: 1 } },
|
||||
})
|
||||
}
|
||||
} catch { /* conversion tracking is best-effort */ }
|
||||
}
|
||||
|
||||
// Log activity
|
||||
const changes = Object.keys(updateData).filter(k => k !== "paidAt" && k !== "cancelledAt")
|
||||
await logActivity({
|
||||
|
||||
Reference in New Issue
Block a user