You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(whatsapp): insert placeholders at cursor - #1434
In the WhatsApp templates editor, clicking "click to insert placeholder" always appends the placeholder to the end of the message instead of inserting it where the typing cursor/pointer is located. Fix the placeholder insertion so it inserts at the active cursor/selection position (tracked in #1432).
Follow the Obra Superpowers engineering procedure end-to-end (research, spec/plan under ~/tools/firstmate/data/flocafe-whatsapp-placeholder-cursor-r1/, TDD red-green-refactor, verification, and no-mistakes validation pipeline). Keep PR title <= 50 chars, single-line PR body paragraphs, and include Fixes #1432.
What Changed
Add insertPlaceholderAtSelection in shared/whatsapp-automation.ts to splice placeholder tokens at the active cursor or selection range while falling back to appending at the end when selection is unestablished or out of bounds.
Update the WhatsApp template editor in frontend/src/app/(dashboard)/whatsapp/page.tsx to track textarea selection state, insert clicked placeholders at the active caret or selection, and restore focus and cursor position after insertion.
Add unit tests in tests/whatsapp-template-placeholder-cursor.test.ts and wire them into npm run test:whatsapp-service in package.json.
✅ Low: The change is well-bounded to a pure placeholder insertion helper and local textarea selection handling in the WhatsApp template editor, with direct unit test coverage and no impact on backend or security boundaries.
Testing
Executed the targeted unit test suite (tests/whatsapp-template-placeholder-cursor.test.ts) and npm run test:script-coverage, built the backend and static desktop frontend (npm run build && npm run build:frontend), and drove all 4 end-user and adversarial scenarios live in Chromium via Playwright against an isolated FloCafe server instance (:4301–:4303), capturing 4 visual screenshot artifacts in the evidence directory; all scenarios passed and transient build/test outputs were cleaned up.
Live validation: ✅ go - 4 of 4 scenarios driven live against the product
Scenario
Result
Live
Evidence
User places the typing cursor in the middle of the WhatsApp template message body and clicks placeholder chips (including consecutive chips); the placeholders insert at the active caret and advance th…
User highlights a text range inside the WhatsApp template message body and clicks a placeholder chip; the selected range is replaced by the placeholder token and the caret rests immediately after the…
User focuses the WhatsApp template message body and places the caret at index 0, then clicks a placeholder chip; the placeholder is prepended at index 0 rather than treated as an untouched field.
Adversarial guard: User switches to a template or clicks 'Reset to default' and immediately clicks a placeholder chip without focusing or clicking the textarea (even when the browser reports selection…
Live validation: ✅ go - 4 of 4 scenarios driven live against the product
Scenario
Result
Live
Evidence
User places the typing cursor in the middle of the WhatsApp template message body and clicks placeholder chips (including consecutive chips); the placeholders insert at the active caret and advance th…
User highlights a text range inside the WhatsApp template message body and clicks a placeholder chip; the selected range is replaced by the placeholder token and the caret rests immediately after the…
User focuses the WhatsApp template message body and places the caret at index 0, then clicks a placeholder chip; the placeholder is prepended at index 0 rather than treated as an untouched field.
Adversarial guard: User switches to a template or clicks 'Reset to default' and immediately clicks a placeholder chip without focusing or clicking the textarea (even when the browser reports selection…
Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.
• Insert WhatsApp template placeholders at the caret or replace selected text instead of appending.
• Restore the caret after insertion and move it to the end when templates switch or reset.
• Add regression tests for insertion positions, selection replacement, fallback, and cursor bounds.
The textarea ref and pure string helper keep selection handling local to the editor and insertion logic independently testable. Mirroring selection in React state or editing the DOM directly would add complexity without a clear benefit.
Files changed (4) +191 / -5
Bug fix (2) +57 / -4
page.tsxInsert template chips at the textarea selection+35/-4
Insert template chips at the textarea selection
• Reads the body textarea’s selection when a placeholder chip is clicked, updates the template body, then refocuses the textarea with the caret after the token. Moves the caret to the end when switching or resetting templates.
• Adds a pure helper that replaces a selected range or inserts at the caret, clamps invalid indices, and appends when no selection is provided. Returns both the updated body and the cursor position after the token.
1. First chip click inserts at the wrong edge✓ Resolved
Description
The caret initialization effect only runs when selectedTemplateId changes, so it misses the first
mount of the lazily rendered automation editor. When the user opens that tab without first focusing
the textarea, the browser selection is 0,0, and the new insertion path places the token at the
beginning instead of preserving the previous append behavior.
ⓘ Recommendations generated based on similar findings in past PRs
Evidence
The editor is rendered inside the automation TabsContent, while the local tabs wrapper forwards
props without enabling forceMount, so inactive content is not mounted. The effect runs only on
selectedTemplateId; its initial run can see a null ref, and switching tabs does not change that
ID. A newly mounted textarea starts with selection 0,0, which the insertion helper treats as a
valid beginning position rather than its null/undefined append fallback.
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
## Issue description
The caret-to-end effect depends only on `selectedTemplateId`, but the automation `TabsContent` is lazily mounted. If the page opens on another tab and the user first switches to automation, the textarea mounts after the effect has already run with no element, leaving its default selection at `0,0`; the first placeholder chip then inserts at the beginning rather than appending when no caret was established.
## Fix Focus Areas
- frontend/src/app/(dashboard)/whatsapp/page.tsx[483-488]
- frontend/src/app/(dashboard)/whatsapp/page.tsx[1362-1382]
- frontend/src/components/ui/tabs.tsx[88-97]
## Recommended Fix
Run the caret initialization when the textarea/editor mounts or otherwise detect the first available textarea after the automation tab becomes active. Ensure the initial selection is moved to the end only when there is no user-established selection, while retaining the existing reset and template-switch behavior.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
In the WhatsApp templates editor, clicking "click to insert placeholder" always appends the placeholder to the end of the message instead of inserting it where the typing cursor/pointer is located. Fix the placeholder insertion so it inserts at the active cursor/selection position (tracked in #1432).
Follow the Obra Superpowers engineering procedure end-to-end (research, spec/plan under
~/tools/firstmate/data/flocafe-whatsapp-placeholder-cursor-r1/, TDD red-green-refactor, verification, andno-mistakesvalidation pipeline). Keep PR title<= 50chars, single-line PR body paragraphs, and includeFixes #1432.What Changed
insertPlaceholderAtSelectioninshared/whatsapp-automation.tsto splice placeholder tokens at the active cursor or selection range while falling back to appending at the end when selection is unestablished or out of bounds.frontend/src/app/(dashboard)/whatsapp/page.tsxto track textarea selection state, insert clicked placeholders at the active caret or selection, and restore focus and cursor position after insertion.tests/whatsapp-template-placeholder-cursor.test.tsand wire them intonpm run test:whatsapp-serviceinpackage.json.Fixes #1432
Risk Assessment
✅ Low: The change is well-bounded to a pure placeholder insertion helper and local textarea selection handling in the WhatsApp template editor, with direct unit test coverage and no impact on backend or security boundaries.
Testing
Executed the targeted unit test suite (
tests/whatsapp-template-placeholder-cursor.test.ts) andnpm run test:script-coverage, built the backend and static desktop frontend (npm run build && npm run build:frontend), and drove all 4 end-user and adversarial scenarios live in Chromium via Playwright against an isolated FloCafe server instance (:4301–:4303), capturing 4 visual screenshot artifacts in the evidence directory; all scenarios passed and transient build/test outputs were cleaned up.Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
./node_modules/.bin/ts-node --transpile-only -P tests/tsconfig.json tests/whatsapp-template-placeholder-cursor.test.tsnpm run test:script-coveragenpm run build && npm run build:frontendcd frontend && E2E_BASE_URL=http://127.0.0.1:4301 E2E_KDS_BASE_URL=http://127.0.0.1:4302 E2E_SERVER_APP_BASE_URL=http://127.0.0.1:4303 npx playwright test e2e/tmp-whatsapp-placeholder-live.spec.ts --config=playwright.config.ts --project=chromium✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.