Dentolize · Send Template in Expired Conversation Walkthrough
On this pageCore paths to testEdge cases worth deliberately tryingOut of scope for this PR (don't file as bugs against it)

For Quality

Core paths to test

  1. Button visibility. Confirm the Send Template button/entry point only appears when a conversation is actually

expired, on both web (Chats.js:142-148) and mobile (WhatsAppChatHeader.js:38-53) — and that it stays hidden on an active conversation.

  1. Picker contents. With a mix of messages in a test company — some with no template, some PENDING, some

REJECTED, some APPROVED — confirm only APPROVED ones appear in the Send Template search (appointmentQueries.js:674-676). Confirm the existing searchMessages usage elsewhere (without approved: true) still returns everything, unaffected.

  1. Name-only filtering. Test with messages containing:
  • No variables at all → eligible.
  • Only @PATIENT_NAME and/or @FIRST_NAME → eligible, preview shows the substituted name.
  • @PATIENT_NAME used twice → still counts as needing one value (dedup via Set), still eligible.
  • Any other variable (@DATE, @DOCTOR_NAME, @AMOUNT, etc.), alone or mixed with a name variable → not

eligible; Send stays disabled and the specific missing variable(s) are listed.

  1. Client/server agreement. Confirm the server rejects a request for an ineligible message even if it somehow

reaches the mutation (e.g. by calling the mutation directly, bypassing the UI) — the server re-derives eligibility itself rather than trusting the client (sendWhatsappTemplate.js:50-56).

  1. Company boundaries. Confirm a message id or conversation id from a different company is rejected

(Message Not Found / Not Authorised), not silently cross-company-leaked.

  1. Permission. Confirm a user without SEND_WA can't send via either entry point (disabled button on web; check

the equivalent mobile permission gate).

  1. WhatsApp-not-connected state. With no officialWhatsApp config (or one with no phoneId), confirm the

mutation fails with WhatsApp Not Connected before attempting any Graph API call or writing any log row.

  1. Send failure handling. Simulate a Graph API failure (e.g. invalid/expired access token, deleted template) and

confirm:

  • A Communication row is still written, with status/waStatus: false and the failure reason in response.
  • The mutation still throws (doesn't silently report success).
  • No ConversationMessage row or conversation-stats update happens on failure (the onlineConversation.update

only runs after the send succeeds).

  1. Send success handling. Confirm on success: a Communication row is logged, a ConversationMessage is created

with the filled-in text, messagesCount/lastActivity update, and if there was an unanswered ConversationFeedback, its responseTime gets backfilled.

  1. Optimistic UI. Confirm the sent message appears immediately at the top/bottom of the message list on both

apps via the Apollo cache update (updateOnNewMessage), and doesn't duplicate once the list is next refetched.

Edge cases worth deliberately trying

  • A conversation with no linked patient record (a raw WhatsApp contact) — confirm the name falls back to the

conversation's own name field, and @FIRST_NAME splits it sensibly even for a single-word name.

  • A message with an empty details string — unfillableVariables/extractValues should treat it as trivially

eligible.

  • RTL languages (Arabic, Kurdish (Sorani/Kurmanji)) — confirm the preview text and the "needs {{val}}" warning render

correctly right-to-left; translations for sendTemplate, sendTemplateDescription, and templateNeedsVariables exist in all eight translation files touched by this PR (ar, ckb, el, en, fr, it, ku, nl, pl).

  • Selecting a message, then clearing the search field (hasClear/allowClear) — confirm the preview and Send state

reset correctly rather than sending a stale selection.

  • Rapid double-submission — confirm the Send button/OK button disables while loading is true, so a second click

can't fire a duplicate send with the same generatedID.

Out of scope for this PR (don't file as bugs against it)

  • Anything about creating or submitting a template to Meta for approval — unrelated existing functionality.
  • Templates needing variables beyond the patient's name — this is an intentional restriction, not a gap (see

Which Templates Qualify).