mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
feat(automations): add 'First Message from Contact' trigger
new_contact_created only fires when the webhook auto-creates the contact row, so it misses the case of manually-added / imported contacts sending their first-ever message. first_inbound_message fires whenever the incoming message is the contact's first customer-sent message (checked by counting prior customer-sender messages in the conversation before insert), which covers both auto-created and pre-existing contacts. - Added first_inbound_message to AutomationTriggerType. - New pill color + dropdown entry labeled "First Message from Contact". - Webhook now counts prior customer messages before inserting the incoming one; dispatches first_inbound_message when the count is 0. - new_contact_created still fires for brand-new contacts; they're independent triggers with overlapping coverage, so users pick. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
da809ced5f
commit
5243188d0c
@ -383,6 +383,17 @@ async function processMessage(
|
||||
? 'image' // stickers are images
|
||||
: 'text' // reaction, unknown → text fallback
|
||||
|
||||
// Determine whether this is the contact's very first inbound message
|
||||
// BEFORE we insert, so the count is accurate. Covers the case where
|
||||
// the contact row already exists (manual add / CSV import) but they've
|
||||
// never messaged us before — which new_contact_created wouldn't catch.
|
||||
const { count: priorCustomerMsgCount } = await supabaseAdmin()
|
||||
.from('messages')
|
||||
.select('id', { count: 'exact', head: true })
|
||||
.eq('conversation_id', conversation.id)
|
||||
.eq('sender_type', 'customer')
|
||||
const isFirstInboundMessage = (priorCustomerMsgCount ?? 0) === 0
|
||||
|
||||
const { error: msgError } = await supabaseAdmin().from('messages').insert({
|
||||
conversation_id: conversation.id,
|
||||
sender_type: 'customer',
|
||||
@ -425,10 +436,20 @@ async function processMessage(
|
||||
// Fire-and-forget: a slow or failing automation must not block the
|
||||
// webhook's 200 OK response to Meta.
|
||||
const inboundText = contentText ?? message.text?.body ?? ''
|
||||
const automationTriggers: ('new_contact_created' | 'new_message_received' | 'keyword_match')[] =
|
||||
contactOutcome.wasCreated
|
||||
? ['new_contact_created', 'new_message_received', 'keyword_match']
|
||||
: ['new_message_received', 'keyword_match']
|
||||
const automationTriggers: (
|
||||
| 'new_contact_created'
|
||||
| 'first_inbound_message'
|
||||
| 'new_message_received'
|
||||
| 'keyword_match'
|
||||
)[] = ['new_message_received', 'keyword_match']
|
||||
// new_contact_created fires only when the webhook just auto-created the
|
||||
// contact row. first_inbound_message fires whenever this is the contact's
|
||||
// first-ever customer-sent message — a superset that also catches
|
||||
// manually-imported contacts sending for the first time. We dispatch both
|
||||
// so users can pick whichever semantic they want; an automation that
|
||||
// listens to only one trigger runs only when that trigger matches.
|
||||
if (contactOutcome.wasCreated) automationTriggers.unshift('new_contact_created')
|
||||
if (isFirstInboundMessage) automationTriggers.unshift('first_inbound_message')
|
||||
for (const triggerType of automationTriggers) {
|
||||
runAutomationsForTrigger({
|
||||
userId,
|
||||
|
||||
@ -106,8 +106,13 @@ const ADDABLE_STEPS: AutomationStepType[] = [
|
||||
|
||||
const TRIGGER_OPTIONS: { value: AutomationTriggerType; label: string; hint: string }[] = [
|
||||
{ value: "new_message_received", label: "New Message Received", hint: "Any incoming message" },
|
||||
{
|
||||
value: "first_inbound_message",
|
||||
label: "First Message from Contact",
|
||||
hint: "First time this contact ever messages you (works for manually-added contacts too)",
|
||||
},
|
||||
{ value: "keyword_match", label: "Keyword Match", hint: "Message contains specific keyword(s)" },
|
||||
{ value: "new_contact_created", label: "New Contact Created", hint: "When a contact is auto-created" },
|
||||
{ value: "new_contact_created", label: "New Contact Created", hint: "When a contact is auto-created from an incoming message" },
|
||||
{ value: "conversation_assigned", label: "Conversation Assigned", hint: "When assigned to an agent" },
|
||||
{ value: "tag_added", label: "Tag Added", hint: "When a tag is added to a contact" },
|
||||
{ value: "time_based", label: "Time-Based", hint: "On a recurring schedule" },
|
||||
|
||||
@ -11,6 +11,10 @@ export const TRIGGER_META: Record<AutomationTriggerType, TriggerMeta> = {
|
||||
label: 'New Message',
|
||||
pillClass: 'border-blue-500/30 bg-blue-500/10 text-blue-300',
|
||||
},
|
||||
first_inbound_message: {
|
||||
label: 'First Message from Contact',
|
||||
pillClass: 'border-teal-500/30 bg-teal-500/10 text-teal-300',
|
||||
},
|
||||
keyword_match: {
|
||||
label: 'Keyword Match',
|
||||
pillClass: 'border-purple-500/30 bg-purple-500/10 text-purple-300',
|
||||
|
||||
@ -214,6 +214,7 @@ export interface BroadcastRecipient {
|
||||
|
||||
export type AutomationTriggerType =
|
||||
| 'new_message_received'
|
||||
| 'first_inbound_message'
|
||||
| 'keyword_match'
|
||||
| 'new_contact_created'
|
||||
| 'conversation_assigned'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user