Skip to content

[Feature]: Show saved contact / push names in the dashboard Chats list (Baileys returns raw JID/@lid instead of the name) #369

@ulises2k

Description

@ulises2k

Pre-flight

Problem / motivation

In the dashboard Chats view, 1:1 conversations are listed by their raw identifier instead of the name the contact is saved under:

  • a bare phone number, or
  • after WhatsApp's LID migration, a raw …@lid id (e.g. 116745901723874@lid).

Both the sidebar chat list and the open-conversation header show this raw id, which makes it very hard to tell who you are talking to. Earlier versions (reported as far back as v0.1.8) showed the saved contact name in the Chats list, so on the current Baileys engine this is effectively a regression.

Example (Baileys engine, session ready): every 1:1 row in the Chats sidebar shows a number / @lid, never a name.

Root cause (already located)

The dashboard is not the problem — it already prefers a name and only falls back to the id:

// dashboard/src/pages/Chats.tsx  (sidebar row ~L703, room header ~L737)
{chat.name || chat.id.split('@')[0]}

The name is dropped server-side, in the Baileys chat mapper:

// src/engine/adapters/baileys-session-store.ts  -> toNeutralChat() (~L124)
return {
  id: c.id,
  name: c.name ?? this.userPart(c.id),   // <-- only Baileys Chat.name, else raw user part
  ...
};

Baileys Chat.name is typically empty for individual chats (it is mainly populated for groups / custom-named chats), so ChatSummary.name becomes the raw user part of the JID/@lid.

The saved name is already available in the same store, it is just never cross-referenced from the chat mapper:

// src/engine/adapters/baileys-session-store.ts  -> toNeutralContact() (~L107)
name: c.name ?? c.verifiedName,   // saved address-book name / business verified name
pushName: c.notify,               // sender's self-set display name

The contacts map is fed from contacts.upsert / contacts.update / messaging-history.set (see baileys.adapter.ts ~L177-183), and for @lid chats the store also already holds a lidToPn map + resolvePhone() (~L92).

Proposed solution

Enrich toNeutralChat() so the chat name falls through a small priority chain before giving up on the raw id:

  1. Baileys Chat.name (groups, custom-named chats) — unchanged.
  2. Contact lookup by chat id in the existing contacts map: name ?? verifiedName ?? notify.
  3. For @lid chats: resolve @lid → phone JID (via the existing lidToPn / phoneNumber) and look up that contact, so hidden-number contacts still resolve once their lid↔pn pair is known.
  4. Raw user part of the JID — current behavior, last resort only.

Illustrative sketch (maintainer can refine):

private toNeutralChat(c: Chat): ChatSummary {
  const last = this.lastMessages.get(c.id);
  return {
    id: c.id,
    name: c.name ?? this.resolveContactName(c.id) ?? this.userPart(c.id),
    isGroup: c.id.endsWith('@g.us'),
    unreadCount: c.unreadCount ?? 0,
    timestamp: last?.timestamp ?? this.toUnixSeconds(c.conversationTimestamp),
    lastMessage: last?.text,
  };
}

private resolveContactName(id: string): string | undefined {
  const pick = (c?: BaileysContactWithPhone) =>
    c?.name ?? c?.verifiedName ?? c?.notify ?? undefined;

  const direct = pick(this.contacts.get(id));
  if (direct) return direct;

  if (id.endsWith('@lid')) {
    const pn = this.lidToPn.get(id) ?? this.contacts.get(id)?.phoneNumber;
    if (pn) {
      return pick(this.contacts.get(pn))
        ?? pick(this.contacts.get(`${this.userPart(pn)}@s.whatsapp.net`));
    }
  }
  return undefined;
}

Notes / caveats:

  • The locally saved name (Contact.name) is the most accurate and should win; verifiedName (WhatsApp Business) and notify (pushName) are reasonable fallbacks. pushName is the sender's own chosen display name, not the saved contact name — still far better than a raw id.
  • Baileys only knows the saved address-book name if WhatsApp delivered it via history sync / contact events. For some hidden-number @lid contacts that never arrives, in which case notify (pushName) is the best available — but the chat row should still prefer it over the raw id.
  • This keeps the fix engine-neutral at the API level: ChatSummary.name simply becomes "best known display name", which is what the dashboard already expects.

Alternatives considered

Scope

  • I understand some features are limited by the underlying WhatsApp engine (e.g. Baileys can only surface the saved name if WhatsApp delivered it via contacts/history sync).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions