From aaa3b019ec8bd2eca9bcf3d203c83ca4c08ef030 Mon Sep 17 00:00:00 2001 From: khaira777 <777gurkirat@gmail.com> Date: Tue, 3 Nov 2026 12:36:23 -0500 Subject: [PATCH 1/3] fix(whatsapp): insert template placeholders at cursor (#1432) --- .../src/app/(dashboard)/whatsapp/page.tsx | 39 +++- package.json | 2 +- shared/whatsapp-automation.ts | 22 +++ ...atsapp-template-placeholder-cursor.test.ts | 167 ++++++++++++++++++ 4 files changed, 225 insertions(+), 5 deletions(-) create mode 100644 tests/whatsapp-template-placeholder-cursor.test.ts diff --git a/frontend/src/app/(dashboard)/whatsapp/page.tsx b/frontend/src/app/(dashboard)/whatsapp/page.tsx index 01dc1c1ea..775f436e5 100644 --- a/frontend/src/app/(dashboard)/whatsapp/page.tsx +++ b/frontend/src/app/(dashboard)/whatsapp/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useState, useCallback } from 'react'; +import { useEffect, useState, useCallback, useRef } from 'react'; import api from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; @@ -49,6 +49,7 @@ import { renderWhatsAppTemplate, buildSampleWhatsAppContext, extractTriggerRule, + insertPlaceholderAtSelection, type WhatsAppAutomationConfig, } from '../../../../../shared/whatsapp-automation'; @@ -322,6 +323,7 @@ export default function WhatsAppPage() { const [automationLoaded, setAutomationLoaded] = useState(false); const [automationLoadError, setAutomationLoadError] = useState(false); const [selectedTemplateId, setSelectedTemplateId] = useState('receipt'); + const templateBodyRef = useRef(null); const [savingAutomation, setSavingAutomation] = useState(false); const [runningSweep, setRunningSweep] = useState(false); const [broadcasting, setBroadcasting] = useState(false); @@ -478,6 +480,13 @@ export default function WhatsAppPage() { void refreshAutomation(); }, [refreshAutomation]); + useEffect(() => { + const el = templateBodyRef.current; + if (!el) return; + const end = el.value.length; + el.setSelectionRange(end, end); + }, [selectedTemplateId]); + const saveAutomation = async () => { if (!automationLoaded || automationLoadError) { toast.error(tCommon('somethingWrong')); @@ -1451,6 +1460,28 @@ export default function WhatsAppPage() { t.id === activeTpl.id ? { ...def } : t, ), })); + requestAnimationFrame(() => { + const el = templateBodyRef.current; + if (!el) return; + el.setSelectionRange(def.body.length, def.body.length); + }); + }; + + const insertTemplatePlaceholder = (token: string) => { + const el = templateBodyRef.current; + const { body: nextBody, cursor: nextCursor } = insertPlaceholderAtSelection( + activeTpl.body, + token, + el?.selectionStart, + el?.selectionEnd, + ); + updateTemplateField('body', nextBody); + requestAnimationFrame(() => { + const target = templateBodyRef.current; + if (!target) return; + target.focus(); + target.setSelectionRange(nextCursor, nextCursor); + }); }; return ( @@ -1489,6 +1520,7 @@ export default function WhatsAppPage() {