When a form has no round-robin assignees, the lead now follows the person the automation assigns to the first call. Co-authored-by: Cursor <cursoragent@cursor.com>
65 lines
2.2 KiB
TypeScript
65 lines
2.2 KiB
TypeScript
export type FormFieldLabel = { key: string; label: string };
|
|
|
|
export type TemplateVars = {
|
|
title: string;
|
|
mobile?: string | null;
|
|
formName?: string | null;
|
|
formValues?: Record<string, unknown> | null;
|
|
};
|
|
|
|
/**
|
|
* مسئول سرنخ فقط از اولین فعالیتی که مسئول دارد پر میشود.
|
|
* اگر قبلاً گرفته شده یا این فعالیت مسئول ندارد، null برمیگردد.
|
|
*/
|
|
export function claimLeadAssignee(
|
|
alreadyClaimed: boolean,
|
|
activityAssigneeId: string | null | undefined,
|
|
): string | null {
|
|
if (alreadyClaimed) return null;
|
|
const id = activityAssigneeId?.trim();
|
|
return id || null;
|
|
}
|
|
|
|
/** counter یکواحد افزایشیافته از AutomationCursor است (از ۱ شروع میشود) */
|
|
export function pickRoundRobin(memberIds: string[], counter: number): string | null {
|
|
const ids = [...new Set(memberIds.filter(Boolean))].sort();
|
|
if (!ids.length) return null;
|
|
const n = Math.max(1, Math.trunc(counter));
|
|
return ids[(n - 1) % ids.length] ?? null;
|
|
}
|
|
|
|
/** جایگزینی {{title}}، {{mobile}}، {{form}} و {{field.<key>}} */
|
|
export function renderAutomationTemplate(text: string, vars: TemplateVars): string {
|
|
return text.replace(/\{\{\s*([\w.\u0600-\u06FF-]+)\s*\}\}/g, (_m, name: string) => {
|
|
if (name === 'title') return vars.title ?? '';
|
|
if (name === 'mobile') return vars.mobile ?? '';
|
|
if (name === 'form') return vars.formName ?? '';
|
|
if (name.startsWith('field.')) {
|
|
const v = vars.formValues?.[name.slice(6)];
|
|
return v == null ? '' : String(v);
|
|
}
|
|
return '';
|
|
});
|
|
}
|
|
|
|
export function formatFormAnswers(
|
|
fields: FormFieldLabel[] | null | undefined,
|
|
values: Record<string, unknown> | null | undefined,
|
|
): string {
|
|
if (!values) return '';
|
|
const lines: string[] = [];
|
|
const seen = new Set<string>();
|
|
for (const f of fields ?? []) {
|
|
seen.add(f.key);
|
|
const raw = values[f.key];
|
|
const v = raw == null ? '' : String(raw).trim();
|
|
if (v) lines.push(`${f.label}: ${v}`);
|
|
}
|
|
for (const [key, raw] of Object.entries(values)) {
|
|
if (seen.has(key)) continue;
|
|
const v = raw == null ? '' : String(raw).trim();
|
|
if (v) lines.push(`${key}: ${v}`);
|
|
}
|
|
return lines.join('\n');
|
|
}
|