feat(crm): add event_reminder_* templates to dev email tester
The pre-event reminder feature shipped with 5 seeded templates
(event_reminder_default + wedding/birthday/corporate/other) but the
CRM → Development "Send any CRM email to me" picker only listed the
quote/invoice/contract templates. Maintainer can now eyeball each
reminder category's body without staging a real event.
Backend:
- Extend TEMPLATES_KEYS in adminDev.js with all 5 reminder keys.
- Add event_date (today+2d), days_before (2), business_name (from
business_profile.legal_name) to the common payload so the
{{tokens}} in the reminder bodies resolve.
Frontend:
- Extend CrmEmailTemplateKey union.
- Add TEMPLATE_LABEL_KEYS entries.
- EN+DE i18n labels under crmDev.templates.label.event_reminder_*.
No PDF attachment — reminders are body-only emails (matches the
real flow).
This commit is contained in:
@@ -98,6 +98,16 @@ const TEMPLATES_KEYS = [
|
||||
'contract_sent',
|
||||
'contract_signed_admin_notification',
|
||||
'contract_fully_signed',
|
||||
// Pre-event reminder emails (migration 143). The runtime resolver
|
||||
// picks `event_reminder_<events.event_type>` with fallback to
|
||||
// `event_reminder_default`. The dev tester exposes every seeded
|
||||
// template so the maintainer can eyeball each category's body
|
||||
// without staging a real event for each.
|
||||
'event_reminder_default',
|
||||
'event_reminder_wedding',
|
||||
'event_reminder_birthday',
|
||||
'event_reminder_corporate',
|
||||
'event_reminder_other',
|
||||
];
|
||||
|
||||
router.get(
|
||||
@@ -355,11 +365,20 @@ async function buildPayloadFor(key, adminId, frontendUrl) {
|
||||
const today = new Date();
|
||||
const dueDate = new Date(today.getTime() - 5 * 86400000);
|
||||
const validUntil = new Date(today.getTime() + 14 * 86400000);
|
||||
// Pre-event reminder mock: pretend the event is 2 days out (the
|
||||
// global default for `crm_event_reminders_days_before`). Renders
|
||||
// {{event_date}} + {{days_before}} for the event_reminder_*
|
||||
// templates.
|
||||
const eventDate = new Date(today.getTime() + 2 * 86400000);
|
||||
const businessProfile = await db('business_profile').first().catch(() => null);
|
||||
|
||||
const common = {
|
||||
customer_name: 'Sample Customer',
|
||||
customer_email: 'sample.customer@example.test',
|
||||
event_name: 'Sample Event',
|
||||
event_date: fakeShortDate(eventDate),
|
||||
days_before: 2,
|
||||
business_name: businessProfile?.legal_name || 'Sample Studio',
|
||||
invoice_number: 'R-DEV-0001',
|
||||
quote_number: 'Q-DEV-0001',
|
||||
total_amount: fakeMoney(total, 'CHF'),
|
||||
|
||||
@@ -3317,6 +3317,26 @@
|
||||
"contract_fully_signed": {
|
||||
"title": "Vertrag beidseitig unterzeichnet",
|
||||
"description": "Beidseitiger Versand, sobald beide Unterschriften vorliegen. Gestempeltes Vertrags-PDF im Anhang."
|
||||
},
|
||||
"event_reminder_default": {
|
||||
"title": "Event-Erinnerung — Standard (Fallback)",
|
||||
"description": "Vor-Event-Erinnerung, wenn keine kategoriespezifische Vorlage zutrifft."
|
||||
},
|
||||
"event_reminder_wedding": {
|
||||
"title": "Event-Erinnerung — Hochzeit",
|
||||
"description": "Vor-Event-Erinnerung für Events mit event_type=wedding."
|
||||
},
|
||||
"event_reminder_birthday": {
|
||||
"title": "Event-Erinnerung — Geburtstag",
|
||||
"description": "Vor-Event-Erinnerung für Events mit event_type=birthday."
|
||||
},
|
||||
"event_reminder_corporate": {
|
||||
"title": "Event-Erinnerung — Firma",
|
||||
"description": "Vor-Event-Erinnerung für Events mit event_type=corporate."
|
||||
},
|
||||
"event_reminder_other": {
|
||||
"title": "Event-Erinnerung — Sonstiges",
|
||||
"description": "Vor-Event-Erinnerung für Events mit event_type=other."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3317,6 +3317,26 @@
|
||||
"contract_fully_signed": {
|
||||
"title": "Contract fully signed (dual-party)",
|
||||
"description": "Dual-party send once both signatures are in. Stamped contract PDF attached."
|
||||
},
|
||||
"event_reminder_default": {
|
||||
"title": "Event reminder — default (catch-all)",
|
||||
"description": "Pre-event nudge used when no per-category template matches."
|
||||
},
|
||||
"event_reminder_wedding": {
|
||||
"title": "Event reminder — wedding",
|
||||
"description": "Pre-event nudge for events with event_type=wedding."
|
||||
},
|
||||
"event_reminder_birthday": {
|
||||
"title": "Event reminder — birthday",
|
||||
"description": "Pre-event nudge for events with event_type=birthday."
|
||||
},
|
||||
"event_reminder_corporate": {
|
||||
"title": "Event reminder — corporate",
|
||||
"description": "Pre-event nudge for events with event_type=corporate."
|
||||
},
|
||||
"event_reminder_other": {
|
||||
"title": "Event reminder — other",
|
||||
"description": "Pre-event nudge for events with event_type=other."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,36 @@ const TEMPLATE_LABEL_KEYS: Record<
|
||||
descKey: 'crmDev.templates.label.contract_fully_signed.description',
|
||||
descFallback: 'Dual-party send once both signatures are in. Stamped contract PDF attached.',
|
||||
},
|
||||
event_reminder_default: {
|
||||
titleKey: 'crmDev.templates.label.event_reminder_default.title',
|
||||
titleFallback: 'Event reminder — default (catch-all)',
|
||||
descKey: 'crmDev.templates.label.event_reminder_default.description',
|
||||
descFallback: 'Pre-event nudge used when no per-category template matches.',
|
||||
},
|
||||
event_reminder_wedding: {
|
||||
titleKey: 'crmDev.templates.label.event_reminder_wedding.title',
|
||||
titleFallback: 'Event reminder — wedding',
|
||||
descKey: 'crmDev.templates.label.event_reminder_wedding.description',
|
||||
descFallback: 'Pre-event nudge for events with event_type=wedding.',
|
||||
},
|
||||
event_reminder_birthday: {
|
||||
titleKey: 'crmDev.templates.label.event_reminder_birthday.title',
|
||||
titleFallback: 'Event reminder — birthday',
|
||||
descKey: 'crmDev.templates.label.event_reminder_birthday.description',
|
||||
descFallback: 'Pre-event nudge for events with event_type=birthday.',
|
||||
},
|
||||
event_reminder_corporate: {
|
||||
titleKey: 'crmDev.templates.label.event_reminder_corporate.title',
|
||||
titleFallback: 'Event reminder — corporate',
|
||||
descKey: 'crmDev.templates.label.event_reminder_corporate.description',
|
||||
descFallback: 'Pre-event nudge for events with event_type=corporate.',
|
||||
},
|
||||
event_reminder_other: {
|
||||
titleKey: 'crmDev.templates.label.event_reminder_other.title',
|
||||
titleFallback: 'Event reminder — other',
|
||||
descKey: 'crmDev.templates.label.event_reminder_other.description',
|
||||
descFallback: 'Pre-event nudge for events with event_type=other.',
|
||||
},
|
||||
};
|
||||
|
||||
export const CrmDevelopmentPage: React.FC = () => {
|
||||
|
||||
@@ -22,7 +22,16 @@ export type CrmEmailTemplateKey =
|
||||
// template_key strings.
|
||||
| 'contract_sent'
|
||||
| 'contract_signed_admin_notification'
|
||||
| 'contract_fully_signed';
|
||||
| 'contract_fully_signed'
|
||||
// Pre-event reminder emails (migration 143). One template per
|
||||
// event_type with a catch-all default. Backend resolves
|
||||
// `event_reminder_<event_type>` then falls back to
|
||||
// `event_reminder_default`.
|
||||
| 'event_reminder_default'
|
||||
| 'event_reminder_wedding'
|
||||
| 'event_reminder_birthday'
|
||||
| 'event_reminder_corporate'
|
||||
| 'event_reminder_other';
|
||||
|
||||
export interface DevEmailTemplateStatus {
|
||||
key: CrmEmailTemplateKey;
|
||||
|
||||
Reference in New Issue
Block a user