113 lines
3.1 KiB
TypeScript
113 lines
3.1 KiB
TypeScript
export type MessageDelayUnit = 'minutes' | 'hours' | 'days' | 'weeks' | 'months';
|
|
|
|
export const MESSAGE_AUTOMATION_TRIGGERS = [
|
|
'person_created',
|
|
'lead_submitted',
|
|
'deal_created',
|
|
'deal_stage_changed',
|
|
'deal_won',
|
|
'deal_lost',
|
|
'ticket_created',
|
|
'ticket_resolved',
|
|
'invoice_issued',
|
|
'invoice_paid',
|
|
'activity_created',
|
|
'activity_done',
|
|
'sms_link_clicked',
|
|
] as const;
|
|
|
|
export const MAX_MESSAGE_REPEAT = 10;
|
|
export const MAX_MESSAGE_SMS = 160;
|
|
|
|
export function delayMs(value: number, unit: MessageDelayUnit): number {
|
|
const n = Math.max(0, Math.trunc(Number(value) || 0));
|
|
if (unit === 'minutes') return n * 60_000;
|
|
if (unit === 'hours') return n * 3_600_000;
|
|
if (unit === 'days') return n * 86_400_000;
|
|
if (unit === 'weeks') return n * 7 * 86_400_000;
|
|
return n * 30 * 86_400_000;
|
|
}
|
|
|
|
export function addDelay(
|
|
from: Date,
|
|
value: number,
|
|
unit: MessageDelayUnit,
|
|
): Date {
|
|
const n = Math.max(0, Math.trunc(Number(value) || 0));
|
|
if (unit === 'months') {
|
|
const next = new Date(from.getTime());
|
|
next.setMonth(next.getMonth() + n);
|
|
return next;
|
|
}
|
|
return new Date(from.getTime() + delayMs(n, unit));
|
|
}
|
|
|
|
export function buildSendAts(
|
|
now: Date,
|
|
startValue: number,
|
|
startUnit: MessageDelayUnit,
|
|
repeatCount: number,
|
|
intervalValue: number,
|
|
intervalUnit: MessageDelayUnit,
|
|
): Date[] {
|
|
const count = Math.min(
|
|
MAX_MESSAGE_REPEAT,
|
|
Math.max(1, Math.trunc(Number(repeatCount) || 1)),
|
|
);
|
|
const first = addDelay(now, startValue, startUnit);
|
|
const times = [first];
|
|
let cursor = first;
|
|
for (let i = 1; i < count; i += 1) {
|
|
cursor = addDelay(cursor, Math.max(1, intervalValue), intervalUnit);
|
|
times.push(cursor);
|
|
}
|
|
return times;
|
|
}
|
|
|
|
export function applyMessageTemplate(
|
|
text: string,
|
|
vars: {
|
|
title?: string;
|
|
name?: string;
|
|
phone?: string;
|
|
date?: string;
|
|
company?: string;
|
|
},
|
|
): string {
|
|
const map: Record<string, string> = {
|
|
title: vars.title ?? '',
|
|
عنوان: vars.title ?? '',
|
|
نام: vars.name ?? '',
|
|
name: vars.name ?? '',
|
|
شماره: vars.phone ?? '',
|
|
phone: vars.phone ?? '',
|
|
تاریخ: vars.date ?? '',
|
|
date: vars.date ?? '',
|
|
شرکت: vars.company ?? '',
|
|
company: vars.company ?? '',
|
|
};
|
|
return text.replace(/\{([^}]+)\}/g, (full, key: string) => {
|
|
const next = map[key.trim()];
|
|
return next === undefined ? full : next;
|
|
});
|
|
}
|
|
|
|
export function clipSms(text: string): string {
|
|
const trimmed = text.trim();
|
|
if (trimmed.length <= MAX_MESSAGE_SMS) return trimmed;
|
|
return `${trimmed.slice(0, MAX_MESSAGE_SMS - 1)}…`;
|
|
}
|
|
|
|
/** When this event happens, cancel leftover messages of these earlier triggers. */
|
|
export function cancelTriggersFor(
|
|
trigger: (typeof MESSAGE_AUTOMATION_TRIGGERS)[number],
|
|
): (typeof MESSAGE_AUTOMATION_TRIGGERS)[number][] {
|
|
if (trigger === 'invoice_paid') return ['invoice_issued'];
|
|
if (trigger === 'ticket_resolved') return ['ticket_created'];
|
|
if (trigger === 'deal_won' || trigger === 'deal_lost') {
|
|
return ['deal_created', 'deal_stage_changed'];
|
|
}
|
|
if (trigger === 'activity_done') return ['activity_created'];
|
|
return [];
|
|
}
|