@fayz-ai/plugin-conversations 0.23.15 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ import type { ConnectorDefinition } from '@fayz-ai/core';
2
+ export declare const EVOLUTION_CONNECTOR_ID = "evolution";
3
+ export declare const evolutionConnectorDef: ConnectorDefinition;
4
+ //# sourceMappingURL=connectorDef.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectorDef.d.ts","sourceRoot":"","sources":["../../../src/integrations/evolution/connectorDef.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,mBAAmB,EAAmB,MAAM,eAAe,CAAA;AAIzE,eAAO,MAAM,sBAAsB,cAAc,CAAA;AAyBjD,eAAO,MAAM,qBAAqB,EAAE,mBA0DnC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationList.d.ts","sourceRoot":"","sources":["../../src/views/ConversationList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAYzB,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAgMrE"}
1
+ {"version":3,"file":"ConversationList.d.ts","sourceRoot":"","sources":["../../src/views/ConversationList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,qBAiMrE"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The foot of the inbox list: a green «Conectar WhatsApp» when no number is
3
+ * connected, otherwise «WhatsApp conectado · Gerenciar». The connector lives
4
+ * in Configurações → Conversas → Conectores, two levels away from where the
5
+ * person notices the inbox is empty; this is the short way there.
6
+ */
7
+ export declare function WhatsAppConnectionFooter(): import("react").JSX.Element;
8
+ //# sourceMappingURL=WhatsAppConnectionFooter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WhatsAppConnectionFooter.d.ts","sourceRoot":"","sources":["../../src/views/WhatsAppConnectionFooter.tsx"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,wBAAgB,wBAAwB,gCAsBvC"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "status": "preview",
5
5
  "dependencies": []
6
6
  },
7
- "version": "0.23.15",
7
+ "version": "0.24.1",
8
8
  "description": "[experimental] Fayz SDK — unified conversations / omni-channel inbox plugin",
9
9
  "type": "module",
10
10
  "sideEffects": false,
@@ -33,9 +33,9 @@
33
33
  "lucide-react": ">=0.400.0 <1.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@fayz-ai/core": "^0.63.0",
37
- "@fayz-ai/ui": "^0.63.0",
38
- "@fayz-ai/admin": "^0.63.0"
36
+ "@fayz-ai/core": "^0.67.0",
37
+ "@fayz-ai/ui": "^0.67.0",
38
+ "@fayz-ai/admin": "^0.67.0"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/react": "^18.3.0",
@@ -1,47 +0,0 @@
1
- import { ConversationsContextProvider, InboxView } from './chunk-LJKLHGFX.js';
2
- import './chunk-HMWUU5O7.js';
3
- import React from 'react';
4
- import { currentAppPath, appHref } from '@fayz-ai/core';
5
- import { jsx } from 'react/jsx-runtime';
6
-
7
- var CHANNELS = ["sms", "whatsapp", "instagram", "email", "webchat"];
8
- function requestedContact() {
9
- try {
10
- const hash = currentAppPath();
11
- const qs = hash.includes("?") ? hash.slice(hash.indexOf("?") + 1) : "";
12
- if (!qs) return null;
13
- const p = new URLSearchParams(qs);
14
- const handle = (p.get("handle") ?? "").trim();
15
- const name = (p.get("name") ?? "").trim();
16
- const personId = (p.get("personId") ?? "").trim() || void 0;
17
- if (!handle) return null;
18
- const raw = (p.get("channel") ?? "whatsapp").toLowerCase();
19
- const channel = CHANNELS.includes(raw) ? raw : "whatsapp";
20
- return { personId, name: name || handle, handle, channel };
21
- } catch {
22
- return null;
23
- }
24
- }
25
- function ConversationsPage({ store, config }) {
26
- React.useEffect(() => {
27
- const wanted = requestedContact();
28
- if (!wanted) {
29
- void store.getState().load();
30
- return;
31
- }
32
- void store.getState().openForPerson(wanted).catch(() => {
33
- void store.getState().load();
34
- });
35
- try {
36
- const hash = currentAppPath();
37
- const clean = hash.includes("?") ? hash.slice(0, hash.indexOf("?")) : hash;
38
- window.history.replaceState(null, "", appHref(clean || "/conversations"));
39
- } catch {
40
- }
41
- }, []);
42
- return /* @__PURE__ */ jsx(ConversationsContextProvider, { store, config, children: /* @__PURE__ */ jsx(InboxView, {}) });
43
- }
44
-
45
- export { ConversationsPage };
46
- //# sourceMappingURL=ConversationsPage-4V4VLM4D.js.map
47
- //# sourceMappingURL=ConversationsPage-4V4VLM4D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/views/ConversationsPage.tsx"],"names":[],"mappings":";;;;;;AAQA,IAAM,WAAsB,CAAC,KAAA,EAAO,UAAA,EAAY,WAAA,EAAa,SAAS,SAAS,CAAA;AAQ/E,SAAS,gBAAA,GAAiG;AACxG,EAAA,IAAI;AACF,IAAA,MAAM,OAAO,cAAA,EAAe;AAC5B,IAAA,MAAM,EAAA,GAAK,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA,GAAI,CAAC,CAAA,GAAI,EAAA;AACpE,IAAA,IAAI,CAAC,IAAI,OAAO,IAAA;AAChB,IAAA,MAAM,CAAA,GAAI,IAAI,eAAA,CAAgB,EAAE,CAAA;AAChC,IAAA,MAAM,UAAU,CAAA,CAAE,GAAA,CAAI,QAAQ,CAAA,IAAK,IAAI,IAAA,EAAK;AAC5C,IAAA,MAAM,QAAQ,CAAA,CAAE,GAAA,CAAI,MAAM,CAAA,IAAK,IAAI,IAAA,EAAK;AACxC,IAAA,MAAM,YAAY,CAAA,CAAE,GAAA,CAAI,UAAU,CAAA,IAAK,EAAA,EAAI,MAAK,IAAK,KAAA,CAAA;AAGrD,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,IAAA,MAAM,OAAO,CAAA,CAAE,GAAA,CAAI,SAAS,CAAA,IAAK,YAAY,WAAA,EAAY;AACzD,IAAA,MAAM,OAAA,GAAW,QAAA,CAAsB,QAAA,CAAS,GAAG,IAAK,GAAA,GAAkB,UAAA;AAC1E,IAAA,OAAO,EAAE,QAAA,EAAU,IAAA,EAAM,IAAA,IAAQ,MAAA,EAAQ,QAAQ,OAAA,EAAQ;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEO,SAAS,iBAAA,CAAkB,EAAE,KAAA,EAAO,MAAA,EAAO,EAG/C;AACD,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,KAAK,KAAA,CAAM,QAAA,EAAS,CAAE,IAAA,EAAK;AAC3B,MAAA;AAAA,IACF;AAKA,IAAA,KAAK,MAAM,QAAA,EAAS,CAAE,cAAc,MAAM,CAAA,CAAE,MAAM,MAAM;AACtD,MAAA,KAAK,KAAA,CAAM,QAAA,EAAS,CAAE,IAAA,EAAK;AAAA,IAC7B,CAAC,CAAA;AAMD,IAAA,IAAI;AACF,MAAA,MAAM,OAAO,cAAA,EAAe;AAC5B,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAC,CAAA,GAAI,IAAA;AACtE,MAAA,MAAA,CAAO,QAAQ,YAAA,CAAa,IAAA,EAAM,IAAI,OAAA,CAAQ,KAAA,IAAS,gBAAgB,CAAC,CAAA;AAAA,IAC1E,CAAA,CAAA,MAAQ;AAAA,IAAoD;AAAA,EAE9D,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,2BACG,4BAAA,EAAA,EAA6B,KAAA,EAAc,MAAA,EAC1C,QAAA,kBAAA,GAAA,CAAC,aAAU,CAAA,EACb,CAAA;AAEJ","file":"ConversationsPage-4V4VLM4D.js","sourcesContent":["import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { ConversationsContextProvider, type ResolvedConversationsConfig } from '../context'\nimport type { ConversationsUIState } from '../store'\nimport type { Channel } from '../types'\nimport { InboxView } from './InboxView'\nimport { currentAppPath, appHref } from '@fayz-ai/core'\n\nconst CHANNELS: Channel[] = ['sms', 'whatsapp', 'instagram', 'email', 'webchat']\n\n/** Quem o link de entrada pediu para abrir.\n *\n * A rota da shell é por hash, então os parâmetros vêm depois do `?` DENTRO do\n * hash — `#/conversations?personId=…`. `window.location.search` está vazio\n * aqui, e foi o primeiro lugar onde procurei.\n */\nfunction requestedContact(): { personId?: string; name: string; handle: string; channel: Channel } | null {\n try {\n const hash = currentAppPath()\n const qs = hash.includes('?') ? hash.slice(hash.indexOf('?') + 1) : ''\n if (!qs) return null\n const p = new URLSearchParams(qs)\n const handle = (p.get('handle') ?? '').trim()\n const name = (p.get('name') ?? '').trim()\n const personId = (p.get('personId') ?? '').trim() || undefined\n // Sem por onde falar não há conversa para abrir. Criar uma thread sem\n // handle produziria um registro que nunca entrega nada.\n if (!handle) return null\n const raw = (p.get('channel') ?? 'whatsapp').toLowerCase()\n const channel = (CHANNELS as string[]).includes(raw) ? (raw as Channel) : 'whatsapp'\n return { personId, name: name || handle, handle, channel }\n } catch {\n return null\n }\n}\n\nexport function ConversationsPage({ store, config }: {\n store: StoreApi<ConversationsUIState>\n config?: ResolvedConversationsConfig\n}) {\n React.useEffect(() => {\n const wanted = requestedContact()\n if (!wanted) {\n void store.getState().load()\n return\n }\n\n // `openForPerson` carrega a caixa sozinho quando precisa, então não há\n // `load()` aqui: os dois juntos disputariam a mesma lista e a thread recém\n // aberta poderia ser substituída pela resposta mais lenta.\n void store.getState().openForPerson(wanted).catch(() => {\n void store.getState().load()\n })\n\n // O parâmetro é uma ORDEM, não um estado: cumprida uma vez, sai da barra de\n // endereços. Sem isto, um F5 meia hora depois reabriria — ou pior,\n // recriaria — a conversa daquela pessoa, e o link ficaria colado no\n // histórico do navegador.\n try {\n const hash = currentAppPath()\n const clean = hash.includes('?') ? hash.slice(0, hash.indexOf('?')) : hash\n window.history.replaceState(null, '', appHref(clean || '/conversations'))\n } catch { /* a barra fica como está; a conversa já abriu */ }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n return (\n <ConversationsContextProvider store={store} config={config}>\n <InboxView />\n </ConversationsContextProvider>\n )\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/data/tables.ts","../src/data/channels.ts","../src/settings/WhatsAppProviders.tsx"],"names":[],"mappings":"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","file":"chunk-3FZX3ZQ3.js","sourcesContent":["// Physical table names for the conversations plugin (plg_conversations* prefix).\n// Import T and reference T.<key> in the data provider so a rename lands in\n// exactly one place.\nexport const T = {\n conversations: 'plg_conversations',\n /** A LEITURA da conversa: a mesma linha, com o dono do lead junto. A escrita\n * continua na tabela — view com `security_invoker` não aceita INSERT aqui. */\n conversationsView: 'v_conversations',\n messages: 'plg_conversation_messages',\n channels: 'plg_conversations_channels',\n} as const\n","// Channel accounts — the numbers a message can leave by (migration 003).\n//\n// Read-only by construction: the table grants members SELECT and nothing else,\n// so this accessor has no write path to offer. Rows are created by the claim\n// function and advanced by the provider's webhooks.\nimport { getSupabaseClientOptional } from '@fayz-ai/core'\nimport { T } from './tables'\nimport type { Channel } from '../types'\n\n/** Whose number it is. `fallback` is the product's, shared by every tenant. */\nexport type MessagingChannelKind = 'fallback' | 'dedicated'\n\n/** The provider's own lifecycle, kept verbatim. Only `active` may carry a send. */\nexport type MessagingChannelStatus =\n | 'requested'\n | 'provisioning'\n | 'provisioned'\n | 'verifying'\n | 'active'\n | 'failed'\n | 'released'\n | 'disconnected'\n\nexport interface MessagingChannelAccount {\n id: string\n /** `null` on the product fallback row — it belongs to the software, not a tenant. */\n tenantId: string | null\n channel: Channel\n provider: string\n providerNumberId: string\n phoneE164: string | null\n kind: MessagingChannelKind\n status: MessagingChannelStatus\n displayName: string | null\n metadata: Record<string, unknown>\n createdAt: string\n updatedAt: string\n}\n\nexport interface ListMessagingChannelsOptions {\n /** Narrow to one provider ('tyxter'). Omitted: every provider in the pool. */\n provider?: string\n /** Narrow to one channel ('whatsapp'). */\n channel?: Channel\n /** Supabase client override; defaults to the globally registered one. */\n supabaseClient?: unknown\n}\n\ntype Row = Record<string, unknown>\n\nfunction mapChannel(r: Row): MessagingChannelAccount {\n return {\n id: String(r.id),\n tenantId: (r.tenant_id as string | null) ?? null,\n channel: (r.channel as Channel) ?? 'whatsapp',\n provider: String(r.provider ?? ''),\n providerNumberId: String(r.provider_number_id ?? ''),\n phoneE164: (r.phone_e164 as string | null) ?? null,\n kind: (r.kind as MessagingChannelKind) ?? 'dedicated',\n status: (r.status as MessagingChannelStatus) ?? 'requested',\n displayName: (r.display_name as string | null) ?? null,\n metadata: (r.metadata as Record<string, unknown>) ?? {},\n createdAt: String(r.created_at ?? ''),\n updatedAt: String(r.updated_at ?? ''),\n }\n}\n\n/**\n * Every number this tenant can send by — its own, plus the product fallback.\n *\n * No tenant filter is applied, and that is deliberate: RLS already returns the\n * tenant's rows and the fallback row, and the fallback has no tenant to filter\n * on. Filtering here would hide exactly the row the panel most needs to show.\n */\nexport async function listMessagingChannels(\n options: ListMessagingChannelsOptions = {},\n): Promise<MessagingChannelAccount[]> {\n const supabase = (options.supabaseClient ?? getSupabaseClientOptional()) as\n | { from: (t: string) => Row }\n | null\n if (!supabase) {\n throw new Error(\n '[plugin-conversations] Supabase client not available. Pass supabaseClient or register the global client via createFayzApp.',\n )\n }\n\n let q = (supabase.from(T.channels) as { select: (s: string) => Row }).select('*')\n if (options.provider) q = (q as { eq: (c: string, v: string) => Row }).eq('provider', options.provider)\n if (options.channel) q = (q as { eq: (c: string, v: string) => Row }).eq('channel', options.channel)\n // Dedicated before fallback: the tenant's own number is the answer whenever\n // there is one, and the readers of this list want it first.\n q = (q as { order: (c: string, o: unknown) => Row }).order('kind', { ascending: true })\n\n const { data, error } = (await q) as { data: Row[] | null; error: unknown }\n if (error) throw error\n return (data ?? []).map(mapChannel)\n}\n\n// ── The claim's lifecycle, as a thing the UI can render ─────────────────────\n//\n// Everything below is PURE. The claim itself is an edge function call and lives\n// in ../integrations/tyxter/data.ts; what belongs here is the vocabulary of the\n// table — which states a number walks through, which of them mean \"still\n// coming\", and which single row is the tenant's own. Keeping it here rather than\n// in the panel is what lets it be tested without React.\n\n/**\n * The happy path, in order. Observed live against the provider's sandbox on\n * 2026-08-24: a provision answered `requested` and the number then walked\n * `provisioned` → `verifying` → `active` in about a second. `provisioning` is in\n * the provider's enum and was not seen at 150ms polling — kept here because the\n * enum has it and a step missing from a timeline reads as a step that failed.\n */\nexport const CHANNEL_CLAIM_TIMELINE: MessagingChannelStatus[] = [\n 'requested',\n 'provisioning',\n 'provisioned',\n 'verifying',\n 'active',\n]\n\n/**\n * The states in which the tenant already has a claim and must not start another.\n *\n * Mirrors `LIVE_CHANNEL_STATUSES` in functions/_shared/tyxter-runtime.js, which\n * is where the edge function enforces it. Two copies because an edge function\n * may not import from src/ — the vitest suite asserts they agree, so a change to\n * one that is not made to the other fails a test rather than letting the panel\n * offer a button the server will refuse.\n */\nexport const LIVE_CHANNEL_STATUSES: MessagingChannelStatus[] = [\n 'requested',\n 'provisioning',\n 'provisioned',\n 'verifying',\n 'active',\n]\n\n/** Terminal, and not a reason to stop the tenant trying again. */\nexport function isDeadChannelStatus(status: MessagingChannelStatus): boolean {\n return !LIVE_CHANNEL_STATUSES.includes(status)\n}\n\n/** On its way, but not carrying messages yet — the state the panel polls in. */\nexport function isPendingChannelStatus(status: MessagingChannelStatus): boolean {\n return LIVE_CHANNEL_STATUSES.includes(status) && status !== 'active'\n}\n\n/** The tenant's own number, live or on its way. Null when they have none. */\nexport function findDedicatedChannel(\n channels: MessagingChannelAccount[],\n tenantId?: string | null,\n): MessagingChannelAccount | null {\n return channels.find(\n (channel) => channel.kind === 'dedicated'\n && (!tenantId || channel.tenantId === tenantId)\n && !isDeadChannelStatus(channel.status),\n ) ?? null\n}\n\n/** The product's shared number, which every tenant sends by until it has its own. */\nexport function findFallbackChannel(\n channels: MessagingChannelAccount[],\n): MessagingChannelAccount | null {\n return channels.find((channel) => channel.kind === 'fallback') ?? null\n}\n\n/**\n * Can this tenant ask for a number right now?\n *\n * The same rule the edge function answers 409 on, asked before the round trip\n * so the button is disabled rather than the click refused.\n */\nexport function canClaimDedicated(\n channels: MessagingChannelAccount[],\n tenantId?: string | null,\n): boolean {\n return findDedicatedChannel(channels, tenantId) === null\n}\n","import React from 'react'\nimport { Check, Loader2, QrCode, RefreshCw, ShieldAlert, ShieldCheck, Zap } from 'lucide-react'\nimport { SettingsGroup } from '@fayz-ai/admin'\nimport { Button, Input, toast } from '@fayz-ai/ui'\nimport { providersApi, type ProviderId, type ProviderRow, type ProviderNumber } from '../data/providers'\n\n/**\n * Onde a casa escolhe por onde o WhatsApp sai.\n *\n * ── os dois não são intercambiáveis, e a tela diz isso ──────────────────\n *\n * A tentação é desenhar dois cartões iguais e um botão de rádio. Seria mentira:\n *\n * Tyxter API oficial. Iniciar conversa EXIGE template aprovado pela Meta.\n * A Meta mede qualidade e limite do número, e responde por eles.\n * Evolution WhatsApp Web. Manda texto para quem quiser, sem template e sem\n * janela — e o número pode ser banido sem aviso.\n *\n * Quem troca de um para o outro precisa saber o que está trocando. Por isso\n * cada cartão carrega a consequência escrita, e não só o nome.\n *\n * ── a chave não volta ───────────────────────────────────────────────────\n *\n * O campo de chave está sempre vazio, mesmo com credencial guardada. Não é\n * esquecimento: o segredo não sai do servidor, nem mascarado, porque\n * `tx_live_••••` ainda é a chave inteira viajando até o navegador para ser\n * escondida na renderização. `hasCredential` responde a única pergunta que a\n * tela precisa fazer — já foi posta? — e o cadeado diz o resto.\n */\n\nconst COPY: Record<ProviderId, {\n name: string\n what: string\n strength: string\n cost: string\n fields: Array<{ key: string; label: string; placeholder: string; secret?: boolean }>\n}> = {\n tyxter: {\n name: 'Tyxter',\n what: 'API oficial do WhatsApp Business, via revenda.',\n strength: 'Entrega confiável, sem risco de banimento. A Meta mede a qualidade do número.',\n cost: 'Para iniciar conversa é obrigatório um template aprovado pela Meta (~1 dia). Texto livre só dentro de 24h da resposta do cliente.',\n fields: [\n { key: 'api_key', label: 'Chave da API', placeholder: 'tx_live_…', secret: true },\n { key: 'default_sender_id', label: 'Número remetente (id)', placeholder: 'cm…' },\n ],\n },\n evolution: {\n name: 'Evolution API',\n what: 'Gateway auto-hospedado, sobre o WhatsApp Web.',\n strength: 'Manda texto livre para quem quiser, sem template e sem janela de 24h.',\n cost: 'O número pode ser banido sem aviso, e a sessão cai sozinha. Aquecer o número não é opcional aqui.',\n fields: [\n { key: 'base_url', label: 'URL da instância', placeholder: 'https://evo.seudominio.com' },\n { key: 'api_key', label: 'Chave da API', placeholder: 'sua apikey', secret: true },\n { key: 'instance', label: 'Nome da instância', placeholder: 'chefcontrol' },\n ],\n },\n}\n\nconst ALL: ProviderId[] = ['tyxter', 'evolution']\n\nfunction StatusChip({ row }: { row: ProviderRow | undefined }) {\n if (!row || row.status === 'unconfigured') {\n return <span className=\"rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground\">não configurado</span>\n }\n const map: Record<string, string> = {\n connected: 'bg-success-soft text-success-soft-foreground',\n connecting: 'bg-warning-soft text-warning-soft-foreground',\n disconnected: 'bg-muted text-muted-foreground',\n error: 'bg-destructive-soft text-destructive-soft-foreground',\n }\n const label: Record<string, string> = {\n connected: 'conectado', connecting: 'aguardando teste',\n disconnected: 'desconectado', error: 'com erro',\n }\n return (\n <span className={`rounded-full px-2 py-0.5 text-[10px] font-medium ${map[row.status] ?? 'bg-muted'}`}>\n {label[row.status] ?? row.status}\n </span>\n )\n}\n\nfunction NumberRow({ n }: { n: ProviderNumber }) {\n return (\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1 py-1.5 text-xs\">\n <span className={`h-1.5 w-1.5 shrink-0 rounded-full ${n.ready ? 'bg-success' : 'bg-muted-foreground/40'}`} />\n <span className=\"font-medium tabular-nums\">{n.phone ?? n.id}</span>\n {n.displayName && <span className=\"text-muted-foreground\">{n.displayName}</span>}\n {/* Qualidade e tier só existem no provedor oficial. Nulo vira \"—\": o\n Evolution não é medido pela Meta, e fingir um \"bom\" aqui seria\n inventar a única informação que decide quanto se pode mandar. */}\n <span className=\"text-muted-foreground\">\n qualidade: <span className=\"text-foreground\">{n.quality ?? '—'}</span>\n </span>\n <span className=\"text-muted-foreground\">\n limite: <span className=\"text-foreground\">{n.tier ?? '—'}</span>\n </span>\n {n.used24h != null && n.allowance != null && (\n <span className=\"text-muted-foreground\">\n 24h: <span className=\"text-foreground tabular-nums\">{n.used24h}/{n.used24h + n.allowance}</span>\n </span>\n )}\n {!n.ready && <span className=\"text-warning\">não pronto para enviar</span>}\n </div>\n )\n}\n\nexport { COPY as WHATSAPP_PROVIDER_COPY }\n\nexport function WhatsAppProviders({ only, onChanged }: {\n /** One provider's card, without the group around it — a connector's detail. */\n only?: ProviderId\n onChanged?: () => void\n} = {}) {\n const [rows, setRows] = React.useState<ProviderRow[] | null>(null)\n const [draft, setDraft] = React.useState<Record<string, Record<string, string>>>({})\n const [busy, setBusy] = React.useState<string | null>(null)\n const [numbers, setNumbers] = React.useState<Record<string, ProviderNumber[]>>({})\n const [qr, setQr] = React.useState<{ provider: string; image: string | null; code: string | null } | null>(null)\n\n const load = React.useCallback(async () => {\n try { setRows(await providersApi.list()) } catch { setRows([]) }\n onChanged?.()\n }, [onChanged])\n React.useEffect(() => { void load() }, [load])\n\n const byId = React.useMemo(\n () => Object.fromEntries((rows ?? []).map((r) => [r.provider, r])) as Record<ProviderId, ProviderRow | undefined>,\n [rows],\n )\n\n function field(p: ProviderId, key: string): string {\n const row = byId[p]\n // A chave nunca é preenchida de volta — ver o cabeçalho.\n if (key === 'api_key') return draft[p]?.[key] ?? ''\n return draft[p]?.[key] ?? String((row?.config as any)?.[key] ?? '')\n }\n\n function setField(p: ProviderId, key: string, v: string) {\n setDraft((d) => ({ ...d, [p]: { ...(d[p] ?? {}), [key]: v } }))\n }\n\n async function run(id: string, fn: () => Promise<void>) {\n setBusy(id)\n try { await fn() } catch (e: any) { toast.error(e?.message ?? 'Falhou') } finally { setBusy(null) }\n }\n\n const save = (p: ProviderId) => run(`save:${p}`, async () => {\n const d = draft[p] ?? {}\n const config: Record<string, unknown> = {}\n for (const f of COPY[p].fields) {\n if (f.secret) continue\n const v = field(p, f.key)\n if (v) config[f.key] = v\n }\n if (p === 'tyxter' && !config.api_base_url) config.api_base_url = 'https://api.tyxter.com'\n await providersApi.save(p, config, d.api_key)\n setDraft((x) => ({ ...x, [p]: { ...(x[p] ?? {}), api_key: '' } }))\n await load()\n toast.success('Guardado')\n })\n\n const test = (p: ProviderId) => run(`test:${p}`, async () => {\n const h = await providersApi.health(p)\n await load()\n toast[h.ok ? 'success' : 'error'](h.ok ? `Conectado — ${h.detail ?? 'ok'}` : `Não conectou: ${h.detail ?? '?'}`)\n })\n\n const refreshNumbers = (p: ProviderId) => run(`numbers:${p}`, async () => {\n const d = await providersApi.numbers(p)\n setNumbers((n) => ({ ...n, [p]: d.numbers }))\n if (d.numbers.length === 0) toast.error('Nenhum número nesta conta')\n })\n\n const activate = (p: ProviderId) => run(`on:${p}`, async () => {\n await providersApi.activate(p)\n await load()\n toast.success(`${COPY[p].name} está valendo agora`)\n })\n\n const pair = (p: ProviderId) => run(`qr:${p}`, async () => {\n const d = await providersApi.pair(p)\n setQr({ provider: p, image: d.qr, code: d.code })\n if (!d.qr && !d.code) toast.error('A instância não devolveu QR — já está pareada?')\n })\n\n const body = (\n <>\n {rows === null && (\n <div className=\"flex items-center gap-2 py-6 text-sm text-muted-foreground\">\n <Loader2 className=\"h-4 w-4 animate-spin\" /> carregando…\n </div>\n )}\n\n {rows !== null && (only ? [only] : ALL).map((p) => {\n const row = byId[p]\n const copy = COPY[p]\n const active = Boolean(row?.isActive)\n const caps = row?.capabilities ?? {}\n\n return (\n <div\n key={p}\n className={`rounded-card border p-4 my-2 ${active ? 'border-primary bg-primary/[0.03]' : 'bg-card'}`}\n data-testid={`provider-${p}`}\n >\n <div className=\"flex flex-wrap items-center gap-2\">\n <span className=\"text-sm font-semibold\">{copy.name}</span>\n {active && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-primary px-2 py-0.5 text-[10px] font-medium text-primary-foreground\">\n <Check className=\"h-3 w-3\" /> valendo agora\n </span>\n )}\n <StatusChip row={row} />\n {row?.hasCredential && (\n <span className=\"inline-flex items-center gap-1 text-[10px] text-muted-foreground\">\n <ShieldCheck className=\"h-3 w-3\" /> chave guardada\n </span>\n )}\n {/* O risco de banimento é a diferença que decide a escolha, e ela\n fica ao lado do nome — não num rodapé que ninguém lê. */}\n {caps.ban_risk === 'high' && (\n <span className=\"inline-flex items-center gap-1 text-[10px] text-warning\">\n <ShieldAlert className=\"h-3 w-3\" /> risco de banimento\n </span>\n )}\n </div>\n\n <p className=\"mt-1 text-xs text-muted-foreground\">{copy.what}</p>\n <div className=\"mt-2 grid gap-1 sm:grid-cols-2\">\n <p className=\"text-[11px] text-success-soft-foreground\">✓ {copy.strength}</p>\n <p className=\"text-[11px] text-warning\">! {copy.cost}</p>\n </div>\n\n <div className=\"mt-3 grid gap-2 sm:grid-cols-2\">\n {copy.fields.map((f) => (\n <label key={f.key} className=\"block\">\n <span className=\"text-[11px] text-muted-foreground\">{f.label}</span>\n <Input\n className=\"mt-0.5 h-8 text-sm\"\n type={f.secret ? 'password' : 'text'}\n autoComplete=\"off\"\n placeholder={f.secret && row?.hasCredential ? '•••••••• (guardada)' : f.placeholder}\n value={field(p, f.key)}\n onChange={(e) => setField(p, f.key, e.target.value)}\n />\n </label>\n ))}\n </div>\n\n <div className=\"mt-3 flex flex-wrap gap-2\">\n <Button size=\"sm\" variant=\"outline\" disabled={busy === `save:${p}`} onClick={() => save(p)}>\n {busy === `save:${p}` ? <Loader2 className=\"h-3 w-3 animate-spin\" /> : 'Guardar'}\n </Button>\n <Button size=\"sm\" variant=\"outline\" disabled={!row?.hasCredential || busy === `test:${p}`} onClick={() => test(p)}>\n {busy === `test:${p}` ? <Loader2 className=\"h-3 w-3 animate-spin\" /> : <><RefreshCw className=\"mr-1 h-3 w-3\" /> Testar</>}\n </Button>\n <Button size=\"sm\" variant=\"outline\" disabled={!row?.hasCredential || busy === `numbers:${p}`} onClick={() => refreshNumbers(p)}>\n Números\n </Button>\n {/* Só aparece onde existe. O Tyxter não pareia por QR, e um botão\n desabilitado ainda promete algo que nunca vai acontecer. */}\n {caps.qr_pairing && (\n <Button size=\"sm\" variant=\"outline\" disabled={!row?.hasCredential || busy === `qr:${p}`} onClick={() => pair(p)}>\n <QrCode className=\"mr-1 h-3 w-3\" /> Parear\n </Button>\n )}\n {!active && (\n <Button size=\"sm\" disabled={!row?.hasCredential || busy === `on:${p}`} onClick={() => activate(p)}>\n <Zap className=\"mr-1 h-3 w-3\" /> Usar este\n </Button>\n )}\n </div>\n\n {numbers[p]?.length ? (\n <div className=\"mt-3 border-t pt-2\">\n {numbers[p].map((n) => <NumberRow key={n.id} n={n} />)}\n </div>\n ) : null}\n\n {qr?.provider === p && (\n <div className=\"mt-3 border-t pt-3\">\n <p className=\"text-xs text-muted-foreground mb-2\">\n Abra o WhatsApp no celular → Aparelhos conectados → Conectar aparelho.\n </p>\n {qr.image && <img src={qr.image} alt=\"QR\" className=\"h-48 w-48 rounded border bg-white p-2\" />}\n {qr.code && <p className=\"mt-2 font-mono text-lg tracking-widest\">{qr.code}</p>}\n </div>\n )}\n </div>\n )\n })}\n </>\n )\n return only ? body : (\n <SettingsGroup\n title=\"WhatsApp — por onde as mensagens saem\"\n description=\"Dois caminhos, um valendo de cada vez. Troque quando quiser; a configuração do outro fica guardada.\"\n >\n {body}\n </SettingsGroup>\n )\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/context.tsx","../src/types.ts","../src/lib/channel.ts","../src/views/shared.tsx","../src/data/channel-connections.ts","../src/views/ConversationList.tsx","../src/views/SendWindow.tsx","../src/views/MessageInspector.tsx","../src/views/MediaBubble.tsx","../src/views/MessageThread.tsx","../src/views/LeadCard.tsx","../src/views/ContactPanel.tsx","../src/views/NewConversationPanel.tsx","../src/lib/campainha.ts","../src/views/useCaixaAoVivo.ts","../src/views/InboxView.tsx"],"names":["React","jsx","React3","jsxs","cn","InboxIcon","CheckCheck","getSupabaseClientOptional","getActiveTenantId","Button","React7","Check","useTranslation","MessageSquare","X","User","Textarea","React11","Fragment"],"mappings":"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","file":"chunk-LJKLHGFX.js","sourcesContent":["import React from 'react'\nimport { useStore, type StoreApi } from 'zustand'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport type { EntityDef } from '@fayz-ai/core'\nimport type { ConversationsUIState } from './store'\n\n/**\n * App-tunable knobs the inbox UI reads. Kept tiny on purpose: everything here\n * describes the APP's data shape (which people are \"contacts\" in this vertical),\n * never product policy.\n */\nexport interface ResolvedConversationsConfig {\n /** `people.kind` the picker searches. */\n contactKind: string\n /** Search source for the contact picker. Defaults to the person archetype. */\n contactLookup?: EntityLookup\n /** The app's own contact entity — \"Create\" opens ITS form. Agenda's twin is `clientEntityDef`. */\n contactEntityDef?: EntityDef\n}\n\nexport const DEFAULT_CONVERSATIONS_CONFIG: ResolvedConversationsConfig = {\n contactKind: 'contact',\n}\n\nconst StoreContext = React.createContext<StoreApi<ConversationsUIState> | null>(null)\nconst ConfigContext = React.createContext<ResolvedConversationsConfig>(DEFAULT_CONVERSATIONS_CONFIG)\n\nexport function ConversationsContextProvider({\n store,\n config = DEFAULT_CONVERSATIONS_CONFIG,\n children,\n}: {\n store: StoreApi<ConversationsUIState>\n config?: ResolvedConversationsConfig\n children?: React.ReactNode\n}) {\n return (\n <StoreContext.Provider value={store}>\n <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>\n </StoreContext.Provider>\n )\n}\n\nexport function useConversationsStore<T>(selector: (state: ConversationsUIState) => T): T {\n const store = React.useContext(StoreContext)\n if (!store) throw new Error('useConversationsStore must be used within ConversationsPage')\n return useStore(store, selector)\n}\n\nexport function useConversationsConfig(): ResolvedConversationsConfig {\n return React.useContext(ConfigContext)\n}\n","// ---------------------------------------------------------------------------\n// @fayz-ai/plugin-conversations — domain types for the unified omni-channel\n// inbox (the GoHighLevel \"Conversations\" equivalent). Provider-agnostic.\n// ---------------------------------------------------------------------------\n\nexport type Channel = 'sms' | 'whatsapp' | 'instagram' | 'email' | 'webchat'\n\nexport type ConversationStatus = 'open' | 'snoozed' | 'closed'\n\nexport type MessageDirection = 'inbound' | 'outbound'\n\nexport interface Conversation {\n id: string\n contactName: string\n /**\n * `public.people` id when the thread is tied to a real contact record (the\n * compose modal resolves one via the shared ContactPicker). Absent for legacy\n * threads and for inbound messages from an unknown handle.\n */\n contactPersonId?: string\n /** Phone, @handle, or email depending on channel */\n contactHandle: string\n channel: Channel\n lastMessagePreview: string\n lastMessageAt: string\n /**\n * Who spoke last: `inbound` = the customer, `outbound` = the house.\n *\n * The field the queue is built on — \"waiting on us\" is `status === 'open'`\n * plus this being `inbound`. `unreadCount` is the older approximation and\n * gets the painful case wrong: a thread somebody opened, read, meant to\n * answer later and forgot has zero unread and a customer still waiting.\n *\n * Optional because a thread predating the column's backfill (or a provider\n * that does not report direction) genuinely does not know — see\n * `isWaitingOnUs`, which falls back rather than guessing.\n */\n lastMessageDirection?: MessageDirection\n unreadCount: number\n /** Quando alguém deu a conversa por vista.\n *\n * Vale enquanto for POSTERIOR a `lastMessageAt`: mensagem nova devolve a\n * conversa à fila sozinha, sem ninguém ter de lembrar de apagar nada. */\n acknowledgedAt?: string | null\n status: ConversationStatus\n /** Quem ATENDE esta conversa. */\n assignedTo?: string\n /** Quem é dono do LEAD — outra pergunta, e a que decide o follow-up.\n * Derivado de `v_leads` pela view `v_conversations`: copiar aqui faria uma\n * segunda verdade que envelhece quando alguém clica \"Assumir\" no funil. */\n leadOwnerId?: string\n leadOwnerName?: string\n /** Tailwind-ish accent for the avatar bubble */\n accent: string\n tags: string[]\n // Optional context shown in the contact panel.\n location?: string\n note?: string\n}\n\nexport interface Message {\n id: string\n conversationId: string\n channel: Channel\n direction: MessageDirection\n body: string\n at: string\n author: string\n /** O que aconteceu com ela depois que saiu. Nulo na entrada — ela chegou,\n * não foi entregue por nós. `failed` é o caso que a tela precisa gritar:\n * uma mensagem que nunca saiu não pode parecer uma mensagem enviada. */\n deliveryStatus?: string | null\n /** O id no provedor. Sem ele, não saiu — e é a chave para buscar o JSON cru. */\n providerMessageId?: string | null\n /**\n * What the provider sent, when it was not plain text. Absent on every row\n * written before migration 012 — absent is \"unknown\", never \"text\", because\n * the rows this exists for are exactly the ones that stored as empty text.\n */\n messageType?: MessageType | null\n /**\n * The part `body` cannot hold: parsed vCards, media metadata, coordinates.\n * Shape follows `messageType`; see functions/_shared/evolution-runtime.js.\n */\n payload?: MessagePayload | null\n /**\n * Where the bytes are, in the private `attachments` bucket — or null, which\n * means one of three ordinary things: the message is text, the row predates\n * 013, or the upload did not happen. Never a URL: the bucket is private and\n * a link has to be signed per view, which `media_url` does against the row\n * rather than against a path the client supplies.\n */\n mediaPath?: string | null\n}\n\nexport type MessageType =\n | 'text' | 'contact' | 'image' | 'video' | 'audio'\n | 'document' | 'sticker' | 'location' | 'reaction' | 'unknown'\n\n/** A contact card someone forwarded into the thread. The number in it is\n * routinely the reason the conversation is happening. */\nexport interface SharedContact {\n name: string\n /** `display` is what a human reads back; `digits` is what dials. */\n phones: Array<{ display: string; digits: string }>\n}\n\nexport interface MessagePayload {\n contacts?: SharedContact[]\n mimetype?: string | null\n fileName?: string | null\n fileLength?: number | null\n seconds?: number | null\n ptt?: boolean | null\n caption?: string | null\n latitude?: number | null\n longitude?: number | null\n name?: string | null\n address?: string | null\n /** Only on `unknown`: the provider keys nobody has mapped yet. */\n keys?: string[]\n}\n\nexport interface ListConversationsQuery {\n channel?: Channel | 'all'\n status?: ConversationStatus | 'all'\n search?: string\n /** Recorta pelo DONO DO LEAD. `'none'` traz quem ainda não é lead de\n * ninguém — a fila que precisa de dono, e a pergunta que a caixa sozinha\n * não respondia. */\n leadOwnerId?: string | 'none'\n}\n\nexport interface SendMessageInput {\n conversationId: string\n body: string\n}\n\nexport interface CreateConversationInput {\n contactName: string\n /** `public.people` id, when the contact was resolved/created by the picker. */\n contactPersonId?: string\n /** Phone, @handle, or email depending on channel. */\n contactHandle?: string\n channel: Channel\n /** Optional first outbound message; stamps preview + last_message_at. */\n firstMessage?: string\n /** Optional free-text note surfaced in the contact panel. */\n note?: string\n}\n\nexport const CHANNEL_LABELS: Record<Channel, string> = {\n sms: 'SMS',\n whatsapp: 'WhatsApp',\n instagram: 'Instagram',\n email: 'Email',\n webchat: 'Web Chat',\n}\n\n/**\n * Is this thread waiting on US?\n *\n * One definition, in one place, because the KPI, the queue table and anything\n * that later filters the inbox have to agree — a dashboard that says three and\n * a list that shows one is worse than neither.\n *\n * `lastMessageDirection` is the real answer. `unreadCount` is the fallback for\n * a thread that genuinely does not know its direction (older than migration\n * 001, or a provider that does not report one) — it under-reports rather than\n * over-reports, which is the right way round: a queue that invents work loses\n * trust faster than one that misses an old row.\n */\nexport function isWaitingOnUs(conversation: Conversation): boolean {\n if (conversation.status !== 'open') return false\n // DAR POR VISTA vence a direção — e só enquanto for mais recente que a\n // última mensagem. Alguém leu, decidiu que não cabe resposta, e tirou da\n // fila; se chegar mensagem depois disso, a comparação se inverte sozinha e a\n // conversa volta. É por isso que é um instante e não um booleano: um\n // booleano precisaria de alguém para apagá-lo, e o dia do esquecimento é o\n // dia em que um cliente fica esperando sem aparecer para ninguém.\n if (conversation.acknowledgedAt && conversation.lastMessageAt\n && conversation.acknowledgedAt >= conversation.lastMessageAt) return false\n if (conversation.lastMessageDirection) return conversation.lastMessageDirection === 'inbound'\n return conversation.unreadCount > 0\n}\n","import React from 'react'\nimport { MessageSquare, Phone, Instagram, Mail, Globe } from 'lucide-react'\nimport { CHANNEL_LABELS, type Channel } from '../types'\n\n// ---------------------------------------------------------------------------\n// Shared channel visuals — one source of truth for the icon + accent color of\n// each channel, reused by the conversation list, thread header and contact\n// panel. Keeps the omni-channel inbox visually consistent.\n// ---------------------------------------------------------------------------\n\nexport const CHANNEL_ICON: Record<Channel, React.ComponentType<{ className?: string }>> = {\n sms: Phone,\n whatsapp: MessageSquare,\n instagram: Instagram,\n email: Mail,\n webchat: Globe,\n}\n\nexport interface ChannelAccent {\n /** Solid brand color (hex) — bubbles, dots, header chips. */\n color: string\n /** Soft tinted background classes for badges. */\n badge: string\n}\n\nexport const CHANNEL_ACCENT: Record<Channel, ChannelAccent> = {\n whatsapp: { color: '#22c55e', badge: 'bg-[#22c55e]/12 text-[#15803d] dark:text-[#4ade80]' },\n sms: { color: '#6366f1', badge: 'bg-[#6366f1]/12 text-[#4338ca] dark:text-[#a5b4fc]' },\n instagram: { color: '#ec4899', badge: 'bg-[#ec4899]/12 text-[#be185d] dark:text-[#f9a8d4]' },\n email: { color: '#0ea5e9', badge: 'bg-[#0ea5e9]/12 text-[#0369a1] dark:text-[#7dd3fc]' },\n webchat: { color: '#f59e0b', badge: 'bg-[#f59e0b]/12 text-[#b45309] dark:text-[#fcd34d]' },\n}\n\nexport { CHANNEL_LABELS }\n","import React from 'react'\nimport { cn } from '@fayz-ai/ui'\nimport { CHANNEL_ACCENT, CHANNEL_ICON, CHANNEL_LABELS } from '../lib/channel'\nimport type { Channel } from '../types'\n\n// ---------------------------------------------------------------------------\n// Small presentational helpers shared across the inbox panes.\n// ---------------------------------------------------------------------------\n\n/** Reactive media-query match — drives the responsive list/thread/panel layout. */\nexport function useMediaQuery(query: string): boolean {\n const [matches, setMatches] = React.useState(\n () => typeof window !== 'undefined' && window.matchMedia(query).matches,\n )\n React.useEffect(() => {\n if (typeof window === 'undefined') return\n const mql = window.matchMedia(query)\n const onChange = () => setMatches(mql.matches)\n onChange()\n mql.addEventListener('change', onChange)\n return () => mql.removeEventListener('change', onChange)\n }, [query])\n return matches\n}\n\nexport function initialsOf(name: string): string {\n return name.replace('@', '').split(/\\s+/).filter(Boolean).map((w) => w[0]).slice(0, 2).join('').toUpperCase()\n}\n\nexport function Avatar({ name, accent, size = 'md', channel }: {\n name: string\n accent: string\n size?: 'sm' | 'md' | 'lg'\n /** When set, renders a small channel glyph badge over the avatar. */\n channel?: Channel\n}) {\n const dims = size === 'lg' ? 'h-14 w-14 text-lg' : size === 'sm' ? 'h-9 w-9 text-xs' : 'h-10 w-10 text-sm'\n const Icon = channel ? CHANNEL_ICON[channel] : null\n return (\n <div className=\"relative shrink-0\">\n <div\n className={cn('flex items-center justify-center rounded-full font-semibold text-white', dims)}\n style={{ backgroundColor: accent }}\n >\n {initialsOf(name)}\n </div>\n {Icon && (\n <span\n className=\"absolute -bottom-0.5 -right-0.5 flex h-4 w-4 items-center justify-center rounded-full ring-2 ring-card\"\n style={{ backgroundColor: CHANNEL_ACCENT[channel!].color }}\n >\n <Icon className=\"h-2.5 w-2.5 text-white\" />\n </span>\n )}\n </div>\n )\n}\n\nexport function ChannelBadge({ channel, className }: { channel: Channel; className?: string }) {\n const Icon = CHANNEL_ICON[channel]\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px] font-medium',\n CHANNEL_ACCENT[channel].badge,\n className,\n )}\n >\n <Icon className=\"h-2.5 w-2.5\" />\n {CHANNEL_LABELS[channel]}\n </span>\n )\n}\n\nexport function relativeTime(iso: string): string {\n const diff = Date.now() - new Date(iso).getTime()\n const mins = Math.round(diff / 60_000)\n if (mins < 1) return 'now'\n if (mins < 60) return `${mins}m`\n const hours = Math.round(mins / 60)\n if (hours < 24) return `${hours}h`\n const days = Math.round(hours / 24)\n if (days < 7) return `${days}d`\n return `${Math.round(days / 7)}w`\n}\n\n/** Day label for the thread date separators. */\nexport function dayLabel(iso: string): string {\n const d = new Date(iso)\n const now = new Date()\n const startOf = (x: Date) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime()\n const dayDiff = Math.round((startOf(now) - startOf(d)) / 86_400_000)\n if (dayDiff <= 0) return 'Today'\n if (dayDiff === 1) return 'Yesterday'\n if (dayDiff < 7) return d.toLocaleDateString([], { weekday: 'long' })\n return d.toLocaleDateString([], { month: 'short', day: 'numeric', year: now.getFullYear() === d.getFullYear() ? undefined : 'numeric' })\n}\n","import * as React from 'react'\nimport { useConnectors } from '@fayz-ai/admin'\nimport { providersApi } from './providers'\nimport type { Channel } from '../types'\n\nlet whatsappCache: Promise<boolean> | null = null\nconst whatsappConnected = () => {\n whatsappCache ??= providersApi.list()\n .then((rows) => rows.some((r) => r.isActive || r.hasCredential))\n .catch(() => { whatsappCache = null; return false })\n return whatsappCache\n}\n\n/**\n * Which channels this house has an account connected for. WhatsApp reads its\n * providers; the others read the inbox's hub connectors. `undefined` while\n * WhatsApp is still being read, so nothing flashes as \"not connected\".\n */\nexport function useChannelConnections(): Partial<Record<Channel, boolean>> | undefined {\n const [whatsapp, setWhatsapp] = React.useState<boolean | undefined>(undefined)\n const { connectors } = useConnectors({ hostPluginId: 'conversations', includeGrants: false })\n React.useEffect(() => {\n let cancelled = false\n void whatsappConnected().then((v) => { if (!cancelled) setWhatsapp(v) })\n return () => { cancelled = true }\n }, [])\n return React.useMemo(() => {\n if (whatsapp === undefined) return undefined\n const live = (needle: string) => (connectors ?? []).some((c) => c.state === 'connected' && c.slug.toLowerCase().includes(needle))\n return { whatsapp: whatsapp || live('whatsapp'), email: live('mail'), instagram: live('instagram') }\n }, [whatsapp, connectors])\n}\n","import React from 'react'\nimport { Search, Inbox as InboxIcon, User, CheckCheck } from 'lucide-react'\nimport { Button, FilterChip, Input, Skeleton, cn } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useConversationsStore } from '../context'\nimport { isWaitingOnUs, type Channel } from '../types'\nimport { Avatar, ChannelBadge, relativeTime } from './shared'\nimport { useChannelConnections } from '../data/channel-connections'\n\n// SMS and web chat are not sold as channels; their old threads still show under \"Todas\".\nconst FILTERS: Array<Channel | 'all'> = ['all', 'whatsapp', 'instagram', 'email']\n\nexport function ConversationList({ className }: { className?: string }) {\n const t = useTranslation()\n const connected = useChannelConnections()\n const {\n conversations, selectedId, channelFilter, leadOwnerFilter, search, loading,\n select, markRead, setChannelFilter, setLeadOwnerFilter, setSearch,\n } = useConversationsStore((s) => s)\n\n // Os donos que a CAIXA conhece — não a equipe inteira. Um recorte que\n // oferece gente sem nenhuma conversa devolve lista vazia e parece defeito.\n // Enquanto um filtro está ativo a lista encolhe, então a opção escolhida\n // entra na marra: sem isso ela some do seletor e não há como desmarcá-la.\n const donos = React.useMemo(() => {\n const vistos = new Map<string, string>()\n for (const c of conversations) {\n if (c.leadOwnerId) vistos.set(c.leadOwnerId, c.leadOwnerName ?? c.leadOwnerId)\n }\n return [...vistos].map(([value, label]) => ({ value, label }))\n }, [conversations])\n\n return (\n <aside className={cn('w-full shrink-0 flex-col border-r border-border bg-card lg:w-[320px]', className)}>\n {/* No title: the shell header already names the page 24px away. Starting\n a conversation moved there too — it is the PAGE's action, not the list's. */}\n <div className=\"border-b border-border px-3 py-3\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n <Input\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n placeholder={t('conversations.list.search')}\n className=\"pl-8\"\n />\n </div>\n <div className=\"mt-2 flex flex-wrap gap-1\">\n {FILTERS.map((id) => {\n // Dashed: no account connected for this channel yet.\n const off = id !== 'all' && connected !== undefined && !connected[id]\n return (\n <Button variant=\"bare\" size=\"bare\"\n key={id}\n onClick={() => setChannelFilter(id)}\n title={off ? t('conversations.filter.notConnected') : undefined}\n className={cn(\n 'rounded-full border px-2.5 py-1 text-xs font-medium transition-colors',\n channelFilter === id\n ? 'border-transparent bg-primary text-primary-foreground'\n : off\n ? 'border-dashed border-muted-foreground/40 bg-transparent text-muted-foreground hover:bg-muted/50'\n : 'border-transparent bg-muted text-muted-foreground hover:bg-muted/70',\n )}\n >\n {t(`conversations.filter.${id}`)}\n </Button>\n )\n })}\n </div>\n {/* O recorte por dono do lead. Some quando a caixa não tem nenhum —\n numa casa sem funil ele seria um seletor com uma opção só. */}\n {donos.length > 0 && (\n <div className=\"mt-2\">\n <FilterChip\n label={t('conversations.contact.leadOwner')}\n icon={User}\n allLabel={t('conversations.filter.anyOwner')}\n options={[{ value: 'none', label: t('conversations.filter.noOwner') }, ...donos]}\n value={leadOwnerFilter}\n onChange={(v) => { void setLeadOwnerFilter(v) }}\n />\n </div>\n )}\n </div>\n\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n {loading && conversations.length === 0 &&\n Array.from({ length: 6 }, (_, i) => (\n <div key={i} className=\"flex w-full items-start gap-3 border-b border-border/50 px-3 py-3\">\n <Skeleton className=\"h-10 w-10 shrink-0 rounded-full\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <Skeleton className=\"h-4 w-28\" />\n <Skeleton className=\"h-3 w-8\" />\n </div>\n <Skeleton className=\"mt-1.5 h-4 w-16 rounded-full\" />\n <Skeleton className=\"mt-1.5 h-3 w-3/4\" />\n </div>\n </div>\n ))}\n {!loading && conversations.length === 0 && (\n <div className=\"flex flex-col items-center gap-2 p-8 text-center text-muted-foreground\">\n <InboxIcon className=\"h-6 w-6\" />\n <p className=\"text-sm\">{t('conversations.list.empty')}</p>\n </div>\n )}\n {conversations.map((c) => {\n const active = c.id === selectedId\n // `isWaitingOnUs` e não `unreadCount > 0`: a conta é uma das duas\n // evidências, e a outra — a última mensagem ser de entrada — é a que\n // sobrevive quando a conta se perde. Ela existe exatamente para isto,\n // e a lista era o único lugar que a ignorava.\n const unread = isWaitingOnUs(c)\n return (\n // `div` em volta e não um botão dentro de outro: HTML não permite\n // aninhar, e o navegador resolve isso silenciosamente movendo o\n // interno para fora — a linha inteira deixa de ser clicável e\n // ninguém entende por quê.\n <div key={c.id} className=\"group relative\">\n <Button variant=\"bare\" size=\"bare\"\n onClick={() => select(c.id)}\n className={cn(\n 'flex w-full items-start justify-start gap-3 rounded-none border-b border-border/50 px-3 py-3 text-left font-normal transition-colors',\n // Um TOM da cor de marca, e não `bg-accent`.\n //\n // `bg-accent` resolve para quase preto neste tema, e a linha da\n // conversa aberta ficava escura sobre escura. Trocar junto o\n // `text-accent-foreground` deixava legível, mas pintava de\n // preto a única linha que se está a ler — chamava mais atenção\n // que a conversa.\n //\n // `bg-primary/10` é um véu: o texto continua com as cores dele,\n // a seleção se lê como seleção e não como bloco, e funciona nos\n // dois temas porque não presume nada sobre o fundo.\n active ? 'bg-primary/10' : 'hover:bg-muted/50',\n )}\n >\n <Avatar name={c.contactName} accent={c.accent} channel={c.channel} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className={cn('truncate text-sm text-foreground', unread ? 'font-semibold' : 'font-medium')}>\n {c.contactName}\n </span>\n <span className={cn('shrink-0 text-[11px]', unread ? 'font-semibold text-primary' : 'text-muted-foreground')}>\n {relativeTime(c.lastMessageAt)}\n </span>\n </div>\n <div className=\"mt-1 flex items-center gap-2\">\n <ChannelBadge channel={c.channel} />\n {c.status !== 'open' && (\n <span className=\"text-[10px] uppercase tracking-wide text-muted-foreground/70\">\n {t(`conversations.status.${c.status}`)}\n </span>\n )}\n {/* O dono do lead NA LINHA, que é o jeito rápido: saber de\n quem é a conversa sem abrir cada uma. Só o primeiro nome —\n \"Carolina Dias\" ao lado do canal empurra a prévia da\n mensagem para fora, e o sobrenome não distingue ninguém\n num time de dois. */}\n {c.leadOwnerName && (\n <span className=\"inline-flex shrink-0 items-center gap-0.5 rounded-full bg-muted px-1.5 text-[10px] text-muted-foreground\">\n <User className=\"h-2.5 w-2.5\" />\n {c.leadOwnerName.split(' ')[0]}\n </span>\n )}\n </div>\n <div className=\"mt-1 flex items-center justify-between gap-2\">\n <span className={cn('truncate text-xs', unread ? 'text-foreground' : 'text-muted-foreground')}>\n {c.lastMessagePreview}\n </span>\n {unread && (\n <span className=\"flex h-[18px] min-w-[18px] shrink-0 items-center justify-center rounded-full bg-destructive px-1.5 text-[10px] font-semibold text-destructive-foreground\">\n {/* Um PONTO quando a conta é zero mas a conversa espera:\n escrever \"0\" ao lado de uma linha destacada diz duas\n coisas contrárias na mesma linha. */}\n {c.unreadCount > 0 ? c.unreadCount : '\\u00b7'}\n </span>\n )}\n </div>\n </div>\n </Button>\n {/* DAR POR VISTA sem abrir.\n O caso é o \"ok, obrigado\" que não pede resposta: ler já tira da\n fila, mas obrigar a abrir trinta conversas para limpar trinta\n bolinhas é trabalho que a lista pode poupar.\n Só aparece quando há o que tirar, e no hover — um botão fixo em\n cada linha competiria com o nome do contato pelo mesmo espaço. */}\n {unread && (\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n title={t('conversations.markRead')}\n aria-label={t('conversations.markRead')}\n onClick={(e) => { e.stopPropagation(); void markRead(c.id) }}\n className=\"absolute right-2 top-2 hidden rounded-full p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground group-hover:block\"\n >\n <CheckCheck className=\"h-3.5 w-3.5\" />\n </Button>\n )}\n </div>\n )\n })}\n </div>\n </aside>\n )\n}\n","import React from 'react'\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport { providersApi, type ProviderRow } from '../data/providers'\n\n/**\n * Se dá para falar com esta pessoa AGORA, e por qual caminho.\n *\n * ── o defeito que isto existe para matar ────────────────────────────────\n *\n * Na API oficial do WhatsApp, texto livre só sai dentro de 24h contadas da\n * última mensagem DO CLIENTE. Fora dela a Meta recusa — e a recusa chega num\n * log, não na tela. O atendente digita, aperta enviar, vê a mensagem aparecer\n * na conversa, e ela nunca chega ao destinatário.\n *\n * Uma tela que aceita o que não vai entregar é pior que uma tela que recusa.\n *\n * ── e por que isso muda com o provedor ──────────────────────────────────\n *\n * No Evolution não existe janela nenhuma: manda sempre. Então o MESMO campo de\n * texto é seguro num provedor e mentiroso no outro, e qual está valendo é uma\n * configuração que muda numa tela distante daqui. Por isso este gancho lê as\n * duas coisas juntas — a janela da conversa E a capacidade do provedor ativo —\n * e devolve uma resposta só: pode escrever, ou não pode e por quê.\n */\n\nexport type SendMode =\n | { kind: 'free'; until: string | null; minutesLeft: number | null }\n | { kind: 'template'; reason: 'window_closed' | 'never_replied' }\n | { kind: 'blocked'; reason: 'no_provider' }\n\nexport interface WindowState {\n loading: boolean\n mode: SendMode\n provider: ProviderRow | undefined\n}\n\ninterface WindowRow {\n window_open: boolean\n window_expires_at: string | null\n minutes_left: number | null\n last_inbound_at: string | null\n}\n\nexport function useSendWindow(conversationId: string | undefined): WindowState {\n const [row, setRow] = React.useState<WindowRow | null>(null)\n const [providers, setProviders] = React.useState<ProviderRow[] | null>(null)\n\n React.useEffect(() => {\n let alive = true\n providersApi.list().then((p) => { if (alive) setProviders(p) }).catch(() => { if (alive) setProviders([]) })\n return () => { alive = false }\n }, [])\n\n React.useEffect(() => {\n let alive = true\n if (!conversationId) { setRow(null); return }\n const sb = getSupabaseClientOptional() as any\n if (!sb) { setRow(null); return }\n sb.from('v_conversations_window')\n .select('window_open, window_expires_at, minutes_left, last_inbound_at')\n .eq('conversation_id', conversationId).eq('tenant_id', getActiveTenantId())\n .maybeSingle()\n .then(({ data }: { data: WindowRow | null }) => { if (alive) setRow(data ?? null) })\n .catch(() => { if (alive) setRow(null) })\n return () => { alive = false }\n }, [conversationId])\n\n const provider = (providers ?? []).find((p) => p.isActive)\n\n const mode = React.useMemo<SendMode>(() => {\n if (!provider) return { kind: 'blocked', reason: 'no_provider' }\n // O provedor que não exige template não tem janela: manda sempre. Dizer\n // \"janela aberta\" aqui seria inventar um conceito que ele não tem.\n if (!provider.capabilities?.requires_template) {\n return { kind: 'free', until: null, minutesLeft: null }\n }\n if (row?.window_open) {\n return { kind: 'free', until: row.window_expires_at, minutesLeft: row.minutes_left }\n }\n return { kind: 'template', reason: row?.last_inbound_at ? 'window_closed' : 'never_replied' }\n }, [row, provider])\n\n return { loading: providers === null, mode, provider }\n}\n\n/** Quanto falta, em português de gente: \"faltam 3h\" e não um carimbo ISO. */\nexport function humanLeft(minutes: number | null | undefined): string {\n if (minutes == null) return ''\n if (minutes < 60) return `${minutes} min`\n const h = Math.floor(minutes / 60)\n return h < 24 ? `${h}h` : `${Math.floor(h / 24)}d`\n}\n\nexport function SendWindowBanner({ state }: { state: WindowState }) {\n const { mode, provider } = state\n if (mode.kind === 'free' && mode.minutesLeft == null) return null\n\n if (mode.kind === 'free') {\n // Aberta, mas fechando. O relógio importa: quem responde quer saber se dá\n // tempo de resolver agora ou se precisa de template.\n const urgent = (mode.minutesLeft ?? 0) < 120\n return (\n <div className={`flex items-center gap-2 px-4 py-1.5 text-[11px] ${urgent ? 'bg-warning-soft text-warning-soft-foreground' : 'text-muted-foreground'}`}>\n <span className=\"h-1.5 w-1.5 rounded-full bg-success\" />\n Janela aberta — texto livre por mais {humanLeft(mode.minutesLeft)}\n </div>\n )\n }\n\n if (mode.kind === 'blocked') {\n return (\n <div className=\"flex items-center gap-2 bg-destructive-soft px-4 py-2 text-[11px] text-destructive-soft-foreground\">\n <span className=\"h-1.5 w-1.5 rounded-full bg-destructive\" />\n Nenhum provedor de WhatsApp ativo — configure em Ajustes › Conversas.\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1 bg-warning-soft px-4 py-2 text-[11px] text-warning-soft-foreground\">\n <span className=\"h-1.5 w-1.5 shrink-0 rounded-full bg-warning\" />\n <span className=\"font-medium\">\n {mode.reason === 'never_replied'\n ? 'Esta pessoa nunca respondeu.'\n : 'A janela de 24 horas fechou.'}\n </span>\n <span>\n No {provider?.provider ?? 'provedor'}, texto livre só sai dentro de 24h da\n resposta do cliente. Para falar agora é preciso um template aprovado.\n </span>\n </div>\n )\n}\n","import React from 'react'\nimport { AlertTriangle, Check, CheckCheck, Clock, Loader2, MoreVertical, X } from 'lucide-react'\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport { Button } from '@fayz-ai/ui'\nimport type { Message } from '../types'\n\n/**\n * O que aconteceu com esta mensagem, e o JSON cru de quem devia tê-la entregue.\n *\n * ── por que isto existe ─────────────────────────────────────────────────\n *\n * Duas mensagens ficaram um dia inteiro na caixa com a mesma cara de qualquer\n * outra — balão verde, horário, tudo igual — e nunca chegaram a ninguém. Não\n * havia como saber olhando. A tela dizia \"enviada\" porque a linha existia no\n * banco, e existir no banco não é ter saído.\n *\n * Uma mensagem que falhou precisa parecer que falhou. E quando alguém\n * perguntar \"por quê?\", a resposta não pode ser \"olha o log do servidor\".\n *\n * ── o JSON vem AO VIVO, e não de uma cópia ──────────────────────────────\n *\n * O status de uma mensagem de WhatsApp muda DEPOIS do envio: aceita, enviada,\n * entregue, lida — às vezes horas depois. Uma cópia gravada no momento do envio\n * envelhece na primeira mudança e passa a mentir com precisão de carimbo.\n * Então o detalhe é buscado no provedor na hora em que alguém abre.\n */\n\nconst STATUS: Record<string, { icon: typeof Check; label: string; cls: string }> = {\n queued: { icon: Clock, label: 'na fila', cls: 'text-white/60' },\n sent: { icon: Check, label: 'enviada', cls: 'text-white/70' },\n delivered: { icon: CheckCheck, label: 'entregue', cls: 'text-white/80' },\n read: { icon: CheckCheck, label: 'lida', cls: 'text-sky-200' },\n failed: { icon: AlertTriangle, label: 'NÃO ENVIADA', cls: 'text-white' },\n expired: { icon: AlertTriangle, label: 'expirou', cls: 'text-white' },\n delivery_timeout: { icon: AlertTriangle, label: 'sem confirmação', cls: 'text-white' },\n cancelled: { icon: X, label: 'cancelada', cls: 'text-white' },\n opted_out: { icon: X, label: 'recusada', cls: 'text-white' },\n}\n\nconst BAD = new Set(['failed', 'expired', 'cancelled', 'opted_out', 'delivery_timeout'])\n\nexport function isFailed(m: Message): boolean {\n if (m.direction !== 'outbound') return false\n // O STATUS MANDA. Ele vem do provedor e é a resposta de quem entregou.\n if (m.deliveryStatus) return BAD.has(m.deliveryStatus)\n\n // Sem status, a ausência de id do provedor é o único sinal que resta — mas\n // ela também é o estado normal nos primeiros segundos, enquanto o envio\n // acontece. Pintar de vermelho nesse intervalo faz a tela acusar de falha\n // uma mensagem que está saindo, e foi exatamente o que aconteceu com uma\n // que já tinha sido entregue.\n //\n // Dois minutos: mais que qualquer envio e menos que a paciência de quem\n // está olhando.\n if (m.providerMessageId) return false\n const age = Date.now() - new Date(m.at).getTime()\n // Uma mensagem em fila para o disparador local pode esperar mais que dois\n // minutos sem que nada esteja errado — ele confere a cada volta e a sessão\n // do WhatsApp pode estar religando.\n return Number.isFinite(age) && age > 120_000\n}\n\n/** O carimbo ao lado da hora. Some nas de entrada: elas chegaram. */\nexport function DeliveryMark({ m }: { m: Message }) {\n if (m.direction !== 'outbound') return null\n const key = isFailed(m) ? 'failed' : (m.deliveryStatus ?? 'sent')\n const cfg = STATUS[key] ?? STATUS.sent\n const Icon = cfg.icon\n return (\n <span className={`inline-flex items-center gap-0.5 ${cfg.cls}`} title={cfg.label}>\n <Icon className=\"h-3 w-3\" />\n {BAD.has(key) && <span className=\"text-[9px] font-semibold uppercase\">{cfg.label}</span>}\n </span>\n )\n}\n\nexport function MessageMenu({ m }: { m: Message }) {\n const [open, setOpen] = React.useState(false)\n const [detail, setDetail] = React.useState<unknown>(null)\n const [loading, setLoading] = React.useState(false)\n const [err, setErr] = React.useState<string | null>(null)\n\n async function load() {\n setOpen(true)\n if (!m.providerMessageId) return\n setLoading(true); setErr(null)\n try {\n const sb = getSupabaseClientOptional() as any\n const { data, error } = await sb.functions.invoke('conversations-provider', {\n body: { tenantId: getActiveTenantId(), action: 'message_detail', providerMessageId: m.providerMessageId },\n })\n if (error) {\n const d = (await error.context?.json?.().catch(() => null)) as { message?: string } | null\n throw new Error(d?.message ?? error.message)\n }\n if ((data as any)?.error) throw new Error((data as any).message ?? (data as any).error)\n setDetail((data as any).detail)\n } catch (e: any) {\n setErr(e?.message ?? 'Não consegui buscar')\n } finally {\n setLoading(false)\n }\n }\n\n return (\n <>\n <Button variant=\"bare\" size=\"bare\"\n onClick={() => void load()}\n aria-label=\"Detalhes da mensagem\"\n className=\"opacity-0 transition-opacity group-hover:opacity-60 hover:!opacity-100\"\n >\n <MoreVertical className=\"h-3.5 w-3.5\" />\n </Button>\n\n {open && (\n <div className=\"fixed inset-0 z-[120] flex items-center justify-center bg-black/50 p-4\" onClick={() => setOpen(false)}>\n <div className=\"max-h-[80vh] w-full max-w-2xl overflow-hidden rounded-card bg-card shadow-2xl\" onClick={(e) => e.stopPropagation()}>\n <div className=\"flex items-center justify-between border-b px-4 py-3\">\n <div>\n <p className=\"text-sm font-semibold\">Detalhes da mensagem</p>\n <p className=\"text-[11px] text-muted-foreground\">\n {new Date(m.at).toLocaleString()} · {m.direction === 'outbound' ? 'saída' : 'entrada'}\n {m.deliveryStatus ? ` · ${m.deliveryStatus}` : ''}\n </p>\n </div>\n <Button variant=\"bare\" size=\"bare\" onClick={() => setOpen(false)} aria-label=\"Fechar\"><X className=\"h-4 w-4\" /></Button>\n </div>\n\n <div className=\"max-h-[60vh] overflow-auto p-4 text-xs\">\n <p className=\"mb-1 font-medium text-muted-foreground\">Nesta base</p>\n <pre className=\"mb-4 overflow-auto rounded bg-muted/40 p-3 text-[11px] leading-relaxed\">\n{JSON.stringify({ id: m.id, direction: m.direction, body: m.body, at: m.at,\n author: m.author, deliveryStatus: m.deliveryStatus,\n providerMessageId: m.providerMessageId }, null, 2)}\n </pre>\n\n <p className=\"mb-1 font-medium text-muted-foreground\">No provedor</p>\n {!m.providerMessageId && (\n // A ausência é a informação: sem id, ninguém do outro lado\n // chegou a aceitar esta mensagem. Ela não atrasou — ela não saiu.\n <p className=\"rounded bg-destructive-soft p-3 text-[11px] text-destructive-soft-foreground\">\n Esta mensagem não tem id no provedor — ela nunca chegou a ser aceita para envio.\n Não há o que buscar do outro lado.\n </p>\n )}\n {loading && <p className=\"flex items-center gap-2 p-3 text-muted-foreground\"><Loader2 className=\"h-3 w-3 animate-spin\" /> buscando…</p>}\n {err && <p className=\"rounded bg-destructive-soft p-3 text-[11px] text-destructive-soft-foreground\">{err}</p>}\n {detail != null && (\n <pre className=\"overflow-auto rounded bg-muted/40 p-3 text-[11px] leading-relaxed\">\n{JSON.stringify(detail, null, 2)}\n </pre>\n )}\n </div>\n </div>\n </div>\n )}\n </>\n )\n}\n","// A mídia que chegou, mostrada — imagem, áudio, vídeo e documento.\n//\n// ── o que faltava, e não era o parser ───────────────────────────────────────\n//\n// A 012 fez a mensagem que não é texto parar de chegar vazia: um áudio entrou\n// classificado como `audio`, `ptt: true`, 23 segundos, `audio/ogg; codecs=opus`,\n// 55.825 bytes. Tudo certo, e a tela mostrava `[áudio]` escrito por extenso,\n// porque saber QUE existe um arquivo não é ter o arquivo.\n//\n// A 013 passou a guardar os bytes no balde `attachments`. Este componente é o\n// outro lado: o que transforma `media_path` em algo que toca.\n//\n// ── por que uma URL assinada por bolha, e não um link no payload ────────────\n//\n// O balde é privado de propósito — uma foto que um lead mandou no WhatsApp não\n// é para o mundo. Privado significa que o navegador não busca sozinho; cada\n// visualização precisa de uma assinatura temporária. Guardar uma URL pronta na\n// linha daria um link que vaza num print e vale para sempre.\n//\n// Quem assina é `conversations-provider`, e ele assina contra a LINHA (o id da\n// mensagem), nunca contra um caminho que o cliente mande — `media_path` começa\n// por `whatsapp/<inquilino>/…` e adivinhar o caminho de outra casa seria\n// trivial.\n//\n// ── por que só ao aparecer ──────────────────────────────────────────────────\n//\n// Uma conversa de vendas tem dezenas de mensagens e a maioria é texto. Assinar\n// tudo ao abrir seria uma chamada por bolha para depois descobrir que só três\n// têm arquivo. `IntersectionObserver` pede quando a bolha entra na tela, que é\n// também quando a assinatura de dez minutos começa a valer a pena.\nimport * as React from 'react'\nimport { Download, FileText } from 'lucide-react'\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport type { Message } from '../types'\n\n/** Os tipos que têm arquivo. Os outros são inteiramente o que `body` e\n * `payload` já dizem, e não têm o que buscar. */\nconst COM_ARQUIVO = new Set(['image', 'video', 'audio', 'document', 'sticker'])\n\nexport function temArquivo(m: Message): boolean {\n return !!m.mediaPath && COM_ARQUIVO.has(String(m.messageType))\n}\n\n/** A URL assinada desta mensagem, pedida quando a bolha aparece.\n *\n * O estado `erro` existe separado de `url === null` porque os dois têm cara\n * diferente na tela: um arquivo que não carregou merece dizer que não\n * carregou, e uma bolha ainda não pedida não deve parecer defeito. */\nfunction useUrlAssinada(m: Message, visivel: boolean) {\n const [url, setUrl] = React.useState<string | null>(null)\n const [erro, setErro] = React.useState(false)\n\n React.useEffect(() => {\n if (!visivel || url || erro || !temArquivo(m)) return\n let vivo = true\n ;(async () => {\n try {\n const sb = getSupabaseClientOptional() as any\n const { data, error } = await sb.functions.invoke('conversations-provider', {\n body: { tenantId: getActiveTenantId(), action: 'media_url', messageId: m.id },\n })\n if (error || (data as any)?.error) throw new Error('falhou')\n if (vivo && (data as any)?.url) setUrl((data as any).url as string)\n else if (vivo) setErro(true)\n } catch {\n if (vivo) setErro(true)\n }\n })()\n return () => { vivo = false }\n }, [visivel, m.id, url, erro])\n\n return { url, erro }\n}\n\n/** `55825` → `55 KB`. Um número de bytes cru não diz a ninguém se vale a pena\n * esperar o download. */\nfunction tamanho(bytes?: number | null): string {\n if (!bytes || bytes <= 0) return ''\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\n/** `23` → `0:23`. A duração é o que decide se dá para ouvir agora. */\nfunction duracao(seg?: number | null): string {\n if (!seg || seg <= 0) return ''\n const m = Math.floor(seg / 60)\n const s = Math.floor(seg % 60)\n return `${m}:${String(s).padStart(2, '0')}`\n}\n\nexport function MediaBubble({ m, outbound }: { m: Message; outbound: boolean }) {\n const ref = React.useRef<HTMLDivElement>(null)\n const [visivel, setVisivel] = React.useState(false)\n const { url, erro } = useUrlAssinada(m, visivel)\n\n React.useEffect(() => {\n const el = ref.current\n // Sem IntersectionObserver (jsdom, navegador antigo) a bolha pede logo:\n // melhor uma chamada a mais do que um anexo que nunca aparece.\n if (!el || typeof IntersectionObserver === 'undefined') { setVisivel(true); return }\n const obs = new IntersectionObserver((entradas) => {\n if (entradas.some((e) => e.isIntersecting)) { setVisivel(true); obs.disconnect() }\n }, { rootMargin: '200px' })\n obs.observe(el)\n return () => obs.disconnect()\n }, [])\n\n const tipo = String(m.messageType)\n const p = (m.payload ?? {}) as { mimetype?: string | null; fileName?: string | null; fileLength?: number | null; seconds?: number | null; ptt?: boolean | null; caption?: string | null }\n const legenda = p.caption ?? null\n\n // O texto que a bolha já mostrava. Continua sendo o que se lê enquanto o\n // arquivo não chegou, e o que se lê para sempre se ele não chegar.\n const rotulo = <p className=\"whitespace-pre-wrap break-words\">{m.body}</p>\n\n if (erro) {\n return (\n <div ref={ref} className=\"space-y-1\">\n {rotulo}\n <p className=\"text-xs opacity-60\">O arquivo não carregou.</p>\n </div>\n )\n }\n\n if (!url) {\n return (\n <div ref={ref} className=\"space-y-1\">\n {rotulo}\n <div className=\"h-1 w-24 animate-pulse rounded bg-current opacity-20\" />\n </div>\n )\n }\n\n if (tipo === 'image' || tipo === 'sticker') {\n return (\n <div ref={ref} className=\"space-y-1\">\n <a href={url} target=\"_blank\" rel=\"noreferrer\">\n <img\n src={url}\n alt={legenda ?? (tipo === 'sticker' ? 'Figurinha' : 'Imagem recebida')}\n className={tipo === 'sticker' ? 'max-h-32 w-auto' : 'max-h-80 w-auto rounded-lg'}\n loading=\"lazy\"\n />\n </a>\n {legenda ? <p className=\"whitespace-pre-wrap break-words\">{legenda}</p> : null}\n </div>\n )\n }\n\n if (tipo === 'video') {\n return (\n <div ref={ref} className=\"space-y-1\">\n <video src={url} controls preload=\"metadata\" className=\"max-h-80 w-auto rounded-lg\" />\n {legenda ? <p className=\"whitespace-pre-wrap break-words\">{legenda}</p> : null}\n </div>\n )\n }\n\n if (tipo === 'audio') {\n return (\n <div ref={ref} className=\"space-y-1\">\n {/* `controls` nativo: o player do sistema já sabe tocar opus, arrastar\n e mudar a velocidade, e um player próprio seria trabalho para\n reimplementar o que o navegador faz melhor. */}\n <audio src={url} controls preload=\"metadata\" className=\"h-9 w-64 max-w-full\" />\n <p className=\"text-xs opacity-60\">\n {p.ptt ? 'Mensagem de voz' : 'Áudio'}\n {duracao(p.seconds) ? ` · ${duracao(p.seconds)}` : ''}\n </p>\n </div>\n )\n }\n\n // Documento: não há o que mostrar no lugar, então mostra-se o que ele É —\n // nome, tamanho e como pegá-lo.\n const nome = p.fileName ?? 'Documento'\n return (\n <div ref={ref} className=\"space-y-1\">\n <a\n href={url}\n target=\"_blank\"\n rel=\"noreferrer\"\n download={nome}\n className={`flex items-center gap-2 rounded-lg border p-2 ${outbound ? 'border-white/30' : 'border-black/10'}`}\n >\n <FileText className=\"h-5 w-5 shrink-0 opacity-70\" />\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm\">{nome}</span>\n {tamanho(p.fileLength) ? <span className=\"block text-xs opacity-60\">{tamanho(p.fileLength)}</span> : null}\n </span>\n <Download className=\"h-4 w-4 shrink-0 opacity-70\" />\n </a>\n {legenda ? <p className=\"whitespace-pre-wrap break-words\">{legenda}</p> : null}\n </div>\n )\n}\n","import React from 'react'\nimport { useSendWindow, SendWindowBanner } from './SendWindow'\nimport { DeliveryMark, MessageMenu, isFailed } from './MessageInspector'\nimport { Send, Clock, Archive, PanelRight, MessageSquare, ChevronLeft, UserRound, Copy, Check } from 'lucide-react'\nimport { Button, Textarea, cn } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useConversationsStore } from '../context'\nimport { CHANNEL_ACCENT, CHANNEL_LABELS } from '../lib/channel'\nimport type { Conversation, Message, SharedContact } from '../types'\nimport { Avatar, ChannelBadge, dayLabel } from './shared'\nimport { MediaBubble, temArquivo } from './MediaBubble'\n\n/**\n * A contact card someone forwarded into the thread.\n *\n * This is the shape the whole 012 change exists for: on 2026-09-22 a lead sent\n * his finance director's card, it rendered as an empty bubble, the SDR asked\n * him to type the number instead, and the screenshot he sent back rendered\n * empty too. The number was in the payload the entire time.\n *\n * The copy button is the point, not decoration — what someone does with a\n * forwarded number within seconds of seeing it is put it somewhere else.\n */\nfunction ContactCard({ contacts, outbound }: { contacts: SharedContact[]; outbound: boolean }) {\n const [copied, setCopied] = React.useState<string | null>(null)\n const copy = (value: string) => {\n void navigator.clipboard?.writeText(value)\n setCopied(value)\n // Long enough to register, short enough that the row is ready again before\n // anyone reaches for a second number on the same card.\n window.setTimeout(() => setCopied((c) => (c === value ? null : c)), 1500)\n }\n return (\n <div className=\"flex flex-col gap-2\">\n {contacts.map((c, i) => (\n <div\n key={`${c.name}-${i}`}\n className={cn(\n 'flex items-start gap-2.5 rounded-xl px-2.5 py-2',\n outbound ? 'bg-white/15' : 'bg-muted',\n )}\n >\n <UserRound className={cn('mt-0.5 h-4 w-4 shrink-0', outbound ? 'text-white/80' : 'text-muted-foreground')} />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-medium\">{c.name}</p>\n {c.phones.map((p) => (\n <Button variant=\"bare\" size=\"bare\"\n key={p.digits}\n type=\"button\"\n onClick={() => copy(p.display)}\n className={cn(\n 'group/phone mt-0.5 flex items-center justify-start gap-1.5 text-left text-[13px] font-normal tabular-nums',\n outbound ? 'text-white/90 hover:text-white' : 'text-muted-foreground hover:text-foreground',\n )}\n >\n {p.display}\n {copied === p.display\n ? <Check className=\"h-3 w-3\" />\n : <Copy className=\"h-3 w-3 opacity-0 transition-opacity group-hover/phone:opacity-100\" />}\n </Button>\n ))}\n </div>\n </div>\n ))}\n </div>\n )\n}\n\n/** The bubble's content. Text is the common case and stays exactly as it was;\n * everything else renders from `messageType`, which is null for any row\n * written before 012 — those fall through to their body, which is what they\n * have. */\nfunction MessageBody({ m, outbound }: { m: Message; outbound: boolean }) {\n const contacts = m.messageType === 'contact' ? m.payload?.contacts ?? [] : []\n if (contacts.length > 0) return <ContactCard contacts={contacts} outbound={outbound} />\n // Desde a 013 os bytes ficam conosco, e a bolha pode ser o arquivo em vez do\n // nome dele. `temArquivo` exige `media_path`: sem ele — texto, linha anterior\n // à 013, ou upload que não aconteceu — cai no rótulo, que é o que existe.\n if (temArquivo(m)) return <MediaBubble m={m} outbound={outbound} />\n return <p className=\"whitespace-pre-wrap break-words\">{m.body}</p>\n}\n\n// Build a flat render list: day-separator rows interleaved with messages, and\n// each message flagged as the start of a new sender-run (WhatsApp grouping).\ntype Row =\n | { kind: 'day'; id: string; label: string }\n | { kind: 'msg'; id: string; message: Message; startsRun: boolean; endsRun: boolean }\n\nfunction buildRows(messages: Message[]): Row[] {\n const rows: Row[] = []\n let lastDay = ''\n messages.forEach((m, i) => {\n const day = new Date(m.at).toDateString()\n if (day !== lastDay) {\n rows.push({ kind: 'day', id: `day-${day}`, label: dayLabel(m.at) })\n lastDay = day\n }\n const prev = messages[i - 1]\n const next = messages[i + 1]\n const samePrev = prev && prev.direction === m.direction && new Date(prev.at).toDateString() === day\n const sameNext = next && next.direction === m.direction && new Date(next.at).toDateString() === day\n rows.push({ kind: 'msg', id: m.id, message: m, startsRun: !samePrev, endsRun: !sameNext })\n })\n return rows\n}\n\nexport function MessageThread({ selected, onTogglePanel, panelOpen, onBack, backAlways, className }: {\n selected: Conversation\n onTogglePanel: () => void\n panelOpen: boolean\n onBack?: () => void\n /** Keep \"back\" on wide screens too: in the floating inbox the list and the\n * thread take turns whatever the viewport is. */\n backAlways?: boolean\n className?: string\n}) {\n const t = useTranslation()\n const { messages, sending, send, setStatus, refreshMessages } = useConversationsStore((s) => s)\n const [draft, setDraft] = React.useState('')\n // Se dá para falar com esta pessoa AGORA, e por qual caminho. Lê a janela de\n // 24h da conversa E a capacidade do provedor ativo: o mesmo campo de texto é\n // seguro num provedor e mentiroso no outro.\n const win = useSendWindow(selected.id)\n const canType = win.mode.kind === 'free'\n const threadRef = React.useRef<HTMLDivElement>(null)\n\n React.useEffect(() => {\n threadRef.current?.scrollTo({ top: threadRef.current.scrollHeight, behavior: 'smooth' })\n }, [messages.length, selected.id])\n\n // O tique duplo chega pelo webhook, no banco, sem passar por aqui. Dez\n // segundos é o intervalo que faz \"entregue\" e \"lida\" aparecerem enquanto a\n // pessoa ainda olha a conversa, e é barato: uma consulta por thread aberta.\n //\n // Para quando a aba sai de foco. Uma caixa esquecida aberta a noite toda não\n // deve consultar 8.640 vezes por nada.\n React.useEffect(() => {\n if (!selected.id) return\n let timer: ReturnType<typeof setInterval> | null = null\n const start = () => { if (!timer) timer = setInterval(() => { void refreshMessages() }, 10_000) }\n const stop = () => { if (timer) { clearInterval(timer); timer = null } }\n const onVis = () => (document.visibilityState === 'visible' ? start() : stop())\n onVis()\n document.addEventListener('visibilitychange', onVis)\n return () => { stop(); document.removeEventListener('visibilitychange', onVis) }\n }, [selected.id, refreshMessages])\n\n async function handleSend() {\n if (!draft.trim()) return\n const body = draft\n setDraft('')\n await send(body)\n }\n\n const accent = CHANNEL_ACCENT[selected.channel]\n const rows = React.useMemo(() => buildRows(messages), [messages])\n\n return (\n <section className={cn('flex min-w-0 flex-1 flex-col bg-muted/20', className)}>\n {/* Header */}\n <div className=\"flex items-center justify-between gap-2 border-b border-border bg-card px-3 py-2.5 md:px-5\">\n <div className=\"flex min-w-0 items-center gap-2 md:gap-3\">\n {onBack && (\n <Button variant=\"ghost\" size=\"icon\" className={cn('-ml-1 shrink-0', !backAlways && 'lg:hidden')} onClick={onBack} aria-label={t('conversations.thread.back')}>\n <ChevronLeft className=\"h-5 w-5\" />\n </Button>\n )}\n <Avatar name={selected.contactName} accent={selected.accent} size=\"sm\" channel={selected.channel} />\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold text-foreground\">{selected.contactName}</p>\n {/* Com o painel de detalhes ABERTO, canal e telefone já estão nele,\n uma coluna ao lado — repetir aqui é a mesma ficha duas vezes na\n mesma linha de leitura. O cabeçalho compacta para avatar + nome. */}\n {!panelOpen && (\n <p className=\"flex items-center gap-1.5 text-xs text-muted-foreground\">\n <ChannelBadge channel={selected.channel} />\n <span className=\"truncate\">{selected.contactHandle}</span>\n </p>\n )}\n </div>\n </div>\n <div className=\"flex shrink-0 items-center gap-1.5\">\n {/* ABRIR O LEAD, no lugar de \"Adiar\" e \"Encerrar\".\n Aqueles dois são vocabulário de suporte — uma fila de chamados que\n se despacha. Aqui a conversa é uma VENDA em andamento: ninguém\n \"encerra\" um lead que respondeu, e adiar é o que a fila da rota já\n faz com data. O que faltava era o caminho da conversa para a\n ficha, e ele não existia em lugar nenhum da tela. */}\n <Button variant=\"outline\" size=\"sm\" onClick={() => setStatus('closed')} aria-label=\"Arquivar\">\n <Archive className=\"h-3.5 w-3.5 sm:mr-1\" /> <span className=\"hidden sm:inline\">Arquivar</span>\n </Button>\n <Button\n variant={panelOpen ? 'secondary' : 'ghost'}\n size=\"icon\"\n onClick={onTogglePanel}\n aria-label={t('conversations.thread.details')}\n >\n <PanelRight className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {/* Messages */}\n <div ref={threadRef} className=\"min-h-0 flex-1 overflow-y-auto px-5 py-4\">\n {rows.map((row) => {\n if (row.kind === 'day') {\n return (\n <div key={row.id} className=\"my-3 flex items-center justify-center\">\n <span className=\"rounded-full bg-muted px-3 py-0.5 text-[11px] font-medium text-muted-foreground\">\n {row.label}\n </span>\n </div>\n )\n }\n const m = row.message\n const outbound = m.direction === 'outbound'\n const failed = isFailed(m)\n return (\n <div\n key={row.id}\n className={cn('group flex items-center gap-1', outbound ? 'justify-end' : 'justify-start', row.startsRun ? 'mt-2.5' : 'mt-0.5')}\n >\n {/* O menu fica FORA do balão e do lado de dentro da conversa, para\n não empurrar o texto nem cobrir a hora. Aparece no hover. */}\n {outbound && <MessageMenu m={m} />}\n <div\n className={cn(\n 'max-w-[68%] px-3.5 py-2 text-sm shadow-sm',\n outbound ? 'rounded-2xl text-white' : 'rounded-2xl bg-card text-foreground',\n // Tail only on the last bubble of a run, on the sender's side.\n outbound && row.endsRun && 'rounded-br-sm',\n !outbound && row.endsRun && 'rounded-bl-sm',\n // UMA MENSAGEM QUE FALHOU PRECISA PARECER QUE FALHOU. Duas\n // ficaram um dia na caixa com a cara de qualquer outra e nunca\n // chegaram a ninguém — não havia como saber olhando.\n outbound && failed && 'ring-2 ring-destructive',\n )}\n style={outbound ? { backgroundColor: failed ? 'hsl(var(--destructive))' : accent.color } : undefined}\n >\n <MessageBody m={m} outbound={outbound} />\n <div className={cn('mt-0.5 flex items-center justify-end gap-1 text-[10px]', outbound ? 'text-white/70' : 'text-muted-foreground')}>\n {new Date(m.at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}\n <DeliveryMark m={m} />\n </div>\n </div>\n {!outbound && <MessageMenu m={m} />}\n </div>\n )\n })}\n {rows.length === 0 && (\n <div className=\"flex h-full flex-col items-center justify-center text-muted-foreground\">\n <MessageSquare className=\"h-7 w-7\" />\n <p className=\"mt-2 text-sm\">{t('conversations.thread.empty')}</p>\n </div>\n )}\n </div>\n\n {/* Composer */}\n {/* TODO(follow-up): wire real emoji picker + attachment upload (removed the\n dead placeholder buttons rather than shipping non-functional UI). */}\n <div className=\"border-t border-border bg-card\">\n <SendWindowBanner state={win} />\n <div className=\"flex items-end gap-2 px-4 py-3\">\n <div className=\"flex-1\">\n <Textarea\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n void handleSend()\n }\n }}\n rows={1}\n disabled={!canType}\n placeholder={\n canType\n ? t('conversations.thread.reply', { channel: CHANNEL_LABELS[selected.channel] })\n : win.mode.kind === 'blocked'\n ? 'Envio bloqueado'\n : 'Fora da janela — envie um template'\n }\n className=\"max-h-32 min-h-[40px] resize-none rounded-md border-border bg-background shadow-none focus:border-primary focus-visible:ring-0 focus-visible:ring-offset-0 disabled:bg-muted/40 disabled:text-muted-foreground disabled:opacity-100\"\n />\n </div>\n <Button onClick={() => void handleSend()} disabled={!canType || sending || !draft.trim()} aria-label={t('conversations.thread.send')}>\n <Send className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </section>\n )\n}\n","import React from 'react'\nimport { ExternalLink, Flame, Snowflake, Sun, Building2 } from 'lucide-react'\nimport { getSupabaseClientOptional, getActiveTenantId, appHref } from '@fayz-ai/core'\n\n/**\n * O lead, dentro da conversa.\n *\n * ── por que estes campos e não a ficha inteira ──────────────────────────\n *\n * Quem está respondendo tem uma pergunta só: \"com quem eu estou falando, e isto\n * é importante?\". A ficha inteira responde isso e mais quarenta coisas, e o\n * custo de ler quarenta é não ler nenhuma.\n *\n * Então: nome, empresa, temperatura, e os motivos que a produziram. O resto\n * está a um clique — e o clique existe, que é o outro defeito que isto conserta:\n * dava para ver o telefone do lead na conversa e não dava para chegar nele.\n *\n * ── sem import entre plugins ────────────────────────────────────────────\n *\n * Isto vive no plugin de conversas e lê tabelas do CRM. Não importa nada de\n * `plugin-crm`: as tabelas são do schema público com RLS por inquilino, e um\n * import amarraria a caixa de entrada a um plugin que pode não estar montado.\n * Mesmo princípio do `TalkToPerson`, que faz o caminho inverso.\n */\n\ninterface LeadBrief {\n id: string\n name: string\n company: string | null\n status: string | null\n sourceName: string | null\n temperature: 'hot' | 'warm' | 'cold' | null\n fitScore: number | null\n interestScore: number | null\n reasons: string[]\n}\n\nconst TEMP: Record<string, { icon: typeof Flame; cls: string; label: string }> = {\n hot: { icon: Flame, cls: 'bg-destructive-soft text-destructive-soft-foreground', label: 'Quente' },\n warm: { icon: Sun, cls: 'bg-warning-soft text-warning-soft-foreground', label: 'Morno' },\n cold: { icon: Snowflake, cls: 'bg-info-soft text-info-soft-foreground', label: 'Frio' },\n}\n\nexport function LeadCard({ personId, handle }: { personId?: string | null; handle?: string | null }) {\n const [lead, setLead] = React.useState<LeadBrief | null | undefined>(undefined)\n\n React.useEffect(() => {\n let alive = true\n const sb = getSupabaseClientOptional() as any\n const tenantId = getActiveTenantId()\n if (!sb || !tenantId || (!personId && !handle)) { setLead(null); return }\n\n ;(async () => {\n try {\n let q = sb.from('people')\n .select('id, name, metadata, phone')\n .eq('tenant_id', tenantId).eq('kind', 'lead').limit(1)\n // Pelo id quando a conversa já está vinculada; pelo telefone quando\n // não — e por DÍGITOS, porque o mesmo número aparece em três grafias.\n q = personId\n ? q.eq('id', personId)\n : q.like('phone', `%${String(handle).replace(/\\D/g, '').slice(-8)}`)\n const { data } = await q.maybeSingle()\n if (!alive) return\n if (!data) { setLead(null); return }\n\n const meta = (data.metadata ?? {}) as any\n let score: any = null\n try {\n const { data: s } = await sb.from('v_crm_lead_score')\n .select('temperature, fit_score, interest_score, reasons')\n .eq('lead_id', data.id).maybeSingle()\n score = s\n } catch { /* sem nota, o cartão mostra o resto */ }\n\n setLead({\n id: data.id, name: data.name,\n company: meta.company ?? null,\n status: meta.status ?? null,\n sourceName: meta.sourceName ?? null,\n temperature: score?.temperature ?? null,\n fitScore: score?.fit_score ?? null,\n interestScore: score?.interest_score ?? null,\n reasons: Array.isArray(score?.reasons) ? score.reasons : [],\n })\n } catch { if (alive) setLead(null) }\n })()\n return () => { alive = false }\n }, [personId, handle])\n\n if (lead === undefined) return <div className=\"px-4 py-3 text-xs text-muted-foreground\">carregando…</div>\n if (!lead) {\n return (\n <div className=\"border-t border-border px-4 py-3\">\n <p className=\"text-xs text-muted-foreground\">\n Este contato ainda não é um lead cadastrado.\n </p>\n </div>\n )\n }\n\n const t = lead.temperature ? TEMP[lead.temperature] : null\n const Icon = t?.icon\n\n return (\n <div className=\"border-t border-border px-4 py-3\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-semibold\">{lead.name}</p>\n {lead.company && (\n <p className=\"flex items-center gap-1 truncate text-xs text-muted-foreground\">\n <Building2 className=\"h-3 w-3 shrink-0\" /> {lead.company}\n </p>\n )}\n </div>\n {/* O caminho que faltava: da conversa para a ficha. */}\n <a\n href={appHref(`/sales/leads/${lead.id}`)}\n className=\"inline-flex shrink-0 items-center gap-1 rounded-button border bg-card px-2 py-1 text-[11px] font-medium hover:bg-muted\"\n >\n Abrir lead <ExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n\n <div className=\"mt-2 flex flex-wrap items-center gap-1.5\">\n {t && Icon && (\n <span className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[10px] font-medium ${t.cls}`}>\n <Icon className=\"h-3 w-3\" /> {t.label}\n {lead.interestScore != null && <span className=\"tabular-nums opacity-70\">{lead.interestScore}</span>}\n </span>\n )}\n {lead.status && (\n <span className=\"rounded-full bg-muted px-2 py-0.5 text-[10px] capitalize text-muted-foreground\">{lead.status}</span>\n )}\n {lead.sourceName && (\n <span className=\"rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground\">{lead.sourceName}</span>\n )}\n </div>\n\n {/* O PORQUÊ da temperatura. Sem ele o chip é um número que ninguém\n confere, e quem está respondendo não sabe o que puxar na conversa. */}\n {lead.reasons.length > 0 && (\n <ul className=\"mt-2 space-y-0.5\">\n {lead.reasons.slice(0, 4).map((r, i) => (\n <li key={i} className=\"flex gap-1.5 text-[11px] text-muted-foreground\">\n <span className=\"text-muted-foreground/40\">•</span><span>{r}</span>\n </li>\n ))}\n </ul>\n )}\n </div>\n )\n}\n","import React from 'react'\nimport { LeadCard } from './LeadCard'\nimport { MapPin, User, Tag, Link2, StickyNote, X } from 'lucide-react'\nimport { Button, cn } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { CHANNEL_LABELS } from '../lib/channel'\nimport type { Conversation } from '../types'\nimport { Avatar, ChannelBadge } from './shared'\n\nfunction Section({ icon: Icon, title, children }: {\n icon: React.ComponentType<{ className?: string }>\n title: string\n children: React.ReactNode\n}) {\n return (\n <div className=\"border-t border-border px-4 py-3\">\n <p className=\"mb-1.5 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n <Icon className=\"h-3 w-3\" /> {title}\n </p>\n {children}\n </div>\n )\n}\n\nexport function ContactPanel({ contact, onClose, className }: {\n contact: Conversation\n onClose?: () => void\n className?: string\n}) {\n const t = useTranslation()\n return (\n <aside className={cn('flex shrink-0 flex-col overflow-y-auto border-l border-border bg-card', className)}>\n {onClose && (\n <div className=\"flex items-center justify-between border-b border-border px-3 py-2 xl:hidden\">\n <span className=\"text-sm font-semibold text-foreground\">{t('conversations.contact.details')}</span>\n <Button variant=\"ghost\" size=\"icon\" onClick={onClose} aria-label={t('conversations.contact.closeDetails')}>\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n )}\n <div className=\"flex flex-col items-center gap-2 px-4 py-5 text-center\">\n <Avatar name={contact.contactName} accent={contact.accent} size=\"lg\" channel={contact.channel} />\n <div>\n <p className=\"text-sm font-semibold text-foreground\">{contact.contactName}</p>\n <p className=\"text-xs text-muted-foreground\">{contact.contactHandle}</p>\n </div>\n <ChannelBadge channel={contact.channel} />\n </div>\n\n {/* O LEAD PRIMEIRO. \"Canal / Status / Responsável\" descrevem a\n conversa; quem está respondendo precisa saber de QUEM ela é — e\n precisa do caminho para a ficha, que não existia. */}\n <LeadCard personId={contact.contactPersonId} handle={contact.contactHandle} />\n\n <Section icon={User} title={t('conversations.contact.details')}>\n <dl className=\"space-y-1.5 text-sm\">\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"text-muted-foreground\">{t('conversations.contact.channel')}</dt>\n <dd className=\"text-foreground\">{CHANNEL_LABELS[contact.channel]}</dd>\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"text-muted-foreground\">{t('conversations.contact.status')}</dt>\n <dd className=\"text-foreground\">{t(`conversations.status.${contact.status}`)}</dd>\n </div>\n {contact.assignedTo && (\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"text-muted-foreground\">{t('conversations.contact.assignedTo')}</dt>\n <dd className=\"text-foreground\">{contact.assignedTo}</dd>\n </div>\n )}\n {/* O dono do LEAD, que é outra pergunta: quem ATENDE esta conversa\n pode não ser quem faz o follow-up no funil. As duas linhas ficam\n lado a lado de propósito — quando divergem, é informação. */}\n {contact.leadOwnerName && (\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"text-muted-foreground\">{t('conversations.contact.leadOwner')}</dt>\n <dd className=\"font-medium text-foreground\">{contact.leadOwnerName}</dd>\n </div>\n )}\n {contact.location && (\n <div className=\"flex items-center justify-between gap-2\">\n <dt className=\"flex items-center gap-1 text-muted-foreground\"><MapPin className=\"h-3 w-3\" /> {t('conversations.contact.location')}</dt>\n <dd className=\"text-foreground\">{contact.location}</dd>\n </div>\n )}\n </dl>\n </Section>\n\n {contact.tags.length > 0 && (\n <Section icon={Tag} title={t('conversations.contact.tags')}>\n <div className=\"flex flex-wrap gap-1.5\">\n {contact.tags.map((tag) => (\n <span key={tag} className=\"rounded-full bg-muted px-2 py-0.5 text-xs font-medium text-foreground\">\n {tag}\n </span>\n ))}\n </div>\n </Section>\n )}\n\n {contact.note && (\n <Section icon={StickyNote} title={t('conversations.contact.note')}>\n <p className=\"text-sm text-foreground\">{contact.note}</p>\n </Section>\n )}\n\n <Section icon={Link2} title={t('conversations.contact.linkedRecords')}>\n <p className=\"text-xs text-muted-foreground\">{t('conversations.contact.noLinkedRecords')}</p>\n </Section>\n </aside>\n )\n}\n","import { errorMessage } from '@fayz-ai/core'\nimport React from 'react'\nimport {\n Button, Textarea, cn, toast,\n Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter,\n} from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport {\n useLimitGuard, invalidateLimit, ContactPicker,\n type ContactPickerValue,\n} from '@fayz-ai/admin'\nimport { useConversationsStore, useConversationsConfig } from '../context'\nimport { CHANNEL_ACCENT, CHANNEL_ICON, CHANNEL_LABELS } from '../lib/channel'\nimport type { Channel } from '../types'\n\nconst CHANNELS: Channel[] = ['whatsapp', 'sms', 'instagram', 'email', 'webchat']\n\n/**\n * Which field of a person IS the handle on a given channel. Phone channels read\n * the phone, email reads the email; Instagram and web chat have no counterpart\n * on a person record, so they always have to be typed. Deliberately NOT\n * cross-filling (an email in a WhatsApp handle looked plausible on screen and\n * was simply wrong).\n */\nfunction personHandleFor(channel: Channel, contact: ContactPickerValue | null): string {\n if (!contact) return ''\n if (channel === 'email') return contact.email ?? ''\n if (channel === 'sms' || channel === 'whatsapp') return contact.phone ?? ''\n return ''\n}\n\nconst HANDLE_LABEL_KEY: Record<Channel, string> = {\n whatsapp: 'conversations.new.handleLabel.phone',\n sms: 'conversations.new.handleLabel.phone',\n email: 'conversations.new.handleLabel.email',\n instagram: 'conversations.new.handleLabel.instagram',\n webchat: 'conversations.new.handleLabel.webchat',\n}\n\n/**\n * Starting a conversation, in a modal.\n *\n * It lived in the right rail for a while, but the inbox is already three\n * columns — list, thread, contact — and a fourth squeezed all of them into\n * slivers. The picker searches existing people by name, which covers the\n * \"does this thread already exist\" check the visible list used to serve.\n */\nexport function NewConversationPanel({\n open,\n onOpenChange,\n}: {\n open: boolean\n onOpenChange: (open: boolean) => void\n}) {\n const t = useTranslation()\n const create = useConversationsStore((s) => s.create)\n const config = useConversationsConfig()\n const guardConversations = useLimitGuard('conversations_month')\n\n const [channel, setChannel] = React.useState<Channel>('whatsapp')\n const [contact, setContact] = React.useState<ContactPickerValue | null>(null)\n // Handle the user typed themselves. The one taken FROM the contact is derived\n // (see personHandleFor) and shown on the picker's chip — same as the agenda,\n // which never had a second phone field.\n const [typedHandle, setTypedHandle] = React.useState('')\n // While the picker's inline create form is open it already asks for phone and\n // email, so showing our own handle field would ask for the phone twice.\n const [creatingContact, setCreatingContact] = React.useState(false)\n const [firstMessage, setFirstMessage] = React.useState('')\n const [submitting, setSubmitting] = React.useState(false)\n\n // Reset the form each time the modal opens. `pickerKey` remounts the picker so\n // its internal search text resets too.\n const [pickerKey, setPickerKey] = React.useState(0)\n React.useEffect(() => {\n if (open) {\n setChannel('whatsapp')\n setContact(null)\n setTypedHandle('')\n setCreatingContact(false)\n setFirstMessage('')\n setSubmitting(false)\n setPickerKey((k) => k + 1)\n }\n }, [open])\n\n // What we'd message on this channel: the contact's own datum when they have\n // one, otherwise whatever the user typed. Recomputed on every channel switch,\n // so flipping WhatsApp → Email swaps phone for email with no stale state.\n const derivedHandle = personHandleFor(channel, contact)\n const effectiveHandle = derivedHandle || typedHandle\n const handleLabel = t(HANDLE_LABEL_KEY[channel])\n\n const canSubmit = (contact?.name.trim().length ?? 0) > 0 && !submitting\n\n async function handleSubmit(e: React.FormEvent) {\n e.preventDefault()\n if (!canSubmit) return\n setSubmitting(true)\n try {\n // Plan quantity guard (client-side, before the store call): opens the\n // global UpgradeModal and aborts when the monthly cap is reached. Inside\n // the try on purpose — it hits the network to count usage, and a rejection\n // out here used to escape unhandled, leaving the modal open with no\n // feedback at all (indistinguishable from a dead button).\n if ((await guardConversations()) === 'blocked') return\n await create({\n channel,\n contactName: contact!.name.trim(),\n contactPersonId: contact?.id,\n contactHandle: effectiveHandle.trim() || undefined,\n firstMessage: firstMessage.trim() || undefined,\n })\n invalidateLimit('conversations_month')\n onOpenChange(false)\n } catch (err) {\n // A failed insert (unresolved tenant, RLS rejection, offline…) previously\n // threw past the `finally` — `onOpenChange(false)` never ran, so the modal\n // stayed open with no feedback and the thread silently vanished. Surface\n // the failure and keep the form open so the user can retry.\n const message = errorMessage(err)\n toast.error(t('conversations.new.createFailed'), { description: message })\n } finally {\n setSubmitting(false)\n }\n }\n\n return (\n <Modal open={open} onOpenChange={onOpenChange}>\n <ModalContent className=\"max-w-md\">\n <ModalHeader>\n <ModalTitle>{t('conversations.new.title')}</ModalTitle>\n </ModalHeader>\n <form onSubmit={handleSubmit} className=\"flex min-h-0 flex-1 flex-col overflow-hidden\">\n <ModalBody className=\"space-y-4\">\n {/* Channel picker */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-muted-foreground\">\n {t('conversations.new.channel')}\n </label>\n <div className=\"flex flex-wrap gap-1.5\">\n {CHANNELS.map((ch) => {\n const Icon = CHANNEL_ICON[ch]\n const active = channel === ch\n return (\n <Button variant=\"bare\" size=\"bare\"\n key={ch}\n type=\"button\"\n onClick={() => setChannel(ch)}\n aria-pressed={active}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-3 py-1.5 text-xs font-medium transition-colors',\n active\n ? 'text-white'\n : 'bg-muted text-muted-foreground hover:bg-muted/70',\n )}\n style={active ? { backgroundColor: CHANNEL_ACCENT[ch].color } : undefined}\n >\n <Icon className=\"h-3 w-3\" />\n {CHANNEL_LABELS[ch]}\n </Button>\n )\n })}\n </div>\n </div>\n\n {/* Contact — shared find-or-create flow (@fayz-ai/admin), the same one\n the agenda uses to pick a client. The picker owns its label, the\n search field, the chip and the channel handle, so this composer and\n the appointment modal render the SAME thing from the same code. */}\n <ContactPicker\n key={pickerKey}\n value={contact}\n onChange={setContact}\n kind={config.contactKind}\n lookup={config.contactLookup}\n createEntityDef={config.contactEntityDef}\n allowFreeText\n onCreatingChange={setCreatingContact}\n autoFocus\n label={t('conversations.new.contactName')}\n placeholder={t('conversations.new.contactNamePlaceholder')}\n secondaryText={derivedHandle || undefined}\n handleField={{\n label: handleLabel,\n derived: derivedHandle || undefined,\n value: typedHandle,\n onChange: setTypedHandle,\n fieldLabel: t('conversations.new.handle'),\n placeholder: t('conversations.new.handlePlaceholder'),\n }}\n />\n\n {/* First message */}\n <div>\n <label htmlFor=\"conv-first-message\" className=\"mb-1.5 block text-xs font-medium text-muted-foreground\">\n {t('conversations.new.firstMessage')}\n </label>\n <Textarea\n id=\"conv-first-message\"\n value={firstMessage}\n onChange={(e) => setFirstMessage(e.target.value)}\n rows={3}\n placeholder={t('conversations.new.firstMessagePlaceholder')}\n className=\"max-h-40 min-h-[64px] resize-none rounded-md border-border bg-background shadow-none focus:border-primary focus-visible:ring-0 focus-visible:ring-offset-0\"\n />\n </div>\n\n </ModalBody>\n {/* No Cancel: the modal header already holds the way out. */}\n <ModalFooter>\n <Button type=\"submit\" disabled={!canSubmit} className=\"w-full\">\n {submitting ? t('conversations.new.creating') : t('conversations.new.create')}\n </Button>\n </ModalFooter>\n </form>\n </ModalContent>\n </Modal>\n )\n}\n","import { getSupabaseClientOptional } from '@fayz-ai/core'\n\n/**\n * UMA assinatura do tópico da conta, partilhada por quem precisar.\n *\n * ── por que não cada um a sua ───────────────────────────────────────────\n *\n * Dois consumidores querem o mesmo sinal: o vigia global (som, contagem,\n * notificação do sistema) e a caixa aberta (lista e thread ao vivo). O jeito\n * óbvio é cada um chamar `supabase.channel('conversas:<tenant>')` — e é o que\n * eu fiz, e está errado.\n *\n * Dois canais com o MESMO tópico no mesmo cliente não recebem os dois: um\n * vence. Testados em separado, ambos funcionam; juntos, um emudece. Em\n * produção quem venceu foi a tela — a mensagem aparecia sozinha e a notificação\n * do sistema não saía, sem erro nenhum para explicar.\n *\n * É o tipo de defeito que só aparece com as duas peças no ar ao mesmo tempo, e\n * por isso passou por dois testes verdes.\n *\n * ── o desenho ───────────────────────────────────────────────────────────\n *\n * Um canal por conta, contado por referências. O primeiro a chegar abre, o\n * último a sair fecha, e todos recebem a mesma campainha.\n */\n\nexport interface Chegada {\n conversationId?: string\n}\n\ntype Ouvinte = (c: Chegada) => void\n\ninterface Assinatura {\n canal: unknown\n ouvintes: Set<Ouvinte>\n}\n\nconst porConta = new Map<string, Assinatura>()\n\n/** Escuta a chegada de mensagem nesta conta. Devolve como deixar de escutar. */\nexport function assinarChegada(tenantId: string, ouvinte: Ouvinte): () => void {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase?.channel || !tenantId) return () => {}\n\n let assinatura = porConta.get(tenantId)\n if (!assinatura) {\n const ouvintes = new Set<Ouvinte>()\n const canal = supabase\n .channel(`conversas:${tenantId}`)\n .on('broadcast', { event: 'inbound' }, (msg: any) => {\n const carga: Chegada = { conversationId: msg?.payload?.conversationId }\n // Cópia antes de percorrer: um ouvinte que se desinscreve ao receber\n // (a tela fechando no mesmo tique) mutaria o Set durante a iteração.\n for (const f of [...ouvintes]) {\n try { f(carga) } catch { /* um ouvinte que falha não cala os outros */ }\n }\n })\n .subscribe()\n assinatura = { canal, ouvintes }\n porConta.set(tenantId, assinatura)\n }\n\n assinatura.ouvintes.add(ouvinte)\n return () => {\n const a = porConta.get(tenantId)\n if (!a) return\n a.ouvintes.delete(ouvinte)\n // O último a sair fecha a porta. Deixar o canal aberto sem ouvintes seria\n // pagar uma conexão por conta que a pessoa visitou e abandonou.\n if (a.ouvintes.size === 0) {\n porConta.delete(tenantId)\n void (getSupabaseClientOptional() as any)?.removeChannel?.(a.canal)\n }\n }\n}\n","import * as React from 'react'\nimport { useActiveTenantId } from '@fayz-ai/core'\n\nimport { useConversationsStore } from '../context'\nimport { assinarChegada } from '../lib/campainha'\n\n/**\n * A caixa aberta se atualiza sozinha quando chega mensagem.\n *\n * ── por que o mesmo tópico do vigia ─────────────────────────────────────\n *\n * O aviso global (som, contagem, notificação do sistema) já escuta\n * `conversas:<tenant>`. A tela aberta precisa exatamente do mesmo sinal, e\n * assinar a TABELA aqui reintroduziria o defeito que levou dois dias para\n * achar: o Realtime resolve a conta pelo JWT, a política resolve por cabeçalho,\n * e quem atende mais de uma casa nunca recebe evento — sem erro nenhum.\n *\n * Dois ouvintes no mesmo tópico não se atrapalham: o servidor entrega a ambos,\n * e cada um faz o que lhe cabe. O vigia avisa; esta tela redesenha.\n *\n * ── por que recarregar em vez de aplicar o payload ──────────────────────\n *\n * A campainha traz só o id da conversa, de propósito — o conteúdo não viaja\n * pelo broadcast. Então a tela vai buscar: `load()` para a lista (que precisa\n * reordenar, atualizar a prévia e a hora) e `refreshMessages()` para a thread,\n * que só escreve se algo mudou e por isso não rouba a seleção de quem lê.\n *\n * É mais uma ida ao servidor do que aplicar o payload à mão, e é o que mantém\n * a tela com a MESMA verdade que um F5 mostraria — sem uma segunda montagem de\n * estado que envelhece em silêncio.\n */\nexport function useCaixaAoVivo() {\n const tenantId = useActiveTenantId()\n const load = useConversationsStore((s) => s.load)\n const refreshMessages = useConversationsStore((s) => s.refreshMessages)\n const selectedId = useConversationsStore((s) => s.selectedId)\n\n // Em refs para que a troca de conversa não derrube e recrie a assinatura:\n // sair e entrar do canal a cada clique na lista perde eventos na janela de\n // reconexão, que é justamente quando se está olhando.\n const abertoRef = React.useRef(selectedId)\n abertoRef.current = selectedId\n\n React.useEffect(() => {\n if (!tenantId) return\n return assinarChegada(tenantId, ({ conversationId }) => {\n void load()\n // A thread só quando é a conversa que está na tela. Recarregar a de\n // outra seria trabalho jogado fora e trocaria o que a pessoa está lendo.\n if (conversationId && conversationId === abertoRef.current) {\n void refreshMessages()\n }\n })\n }, [tenantId, load, refreshMessages])\n}\n","import React from 'react'\nimport { MessageSquare, SquarePen } from 'lucide-react'\nimport { Button, PageHeaderActions, cn } from '@fayz-ai/ui'\nimport { PageActions, useRightRailStore, type PageAction } from '@fayz-ai/admin'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useConversationsStore } from '../context'\nimport { ConversationList } from './ConversationList'\nimport { MessageThread } from './MessageThread'\nimport { ContactPanel } from './ContactPanel'\nimport { NewConversationPanel } from './NewConversationPanel'\nimport { useMediaQuery } from './shared'\nimport { useCaixaAoVivo } from './useCaixaAoVivo'\n\n/**\n * `page` follows the viewport. In the floating inbox the panel is narrower than\n * the screen, so the layout follows the panel: `dock` takes turns between list\n * and thread, `dock-wide` puts them side by side. The contact panel always\n * slides over in a dock.\n */\nexport type InboxLayout = 'page' | 'dock' | 'dock-wide'\n\nexport function InboxView({ layout = 'page', newSignal = 0 }: {\n layout?: InboxLayout\n /** In a dock the \"new conversation\" button lives in the dock's header (the\n * page header belongs to the screen behind); each bump opens the composer. */\n newSignal?: number\n} = {}) {\n const t = useTranslation()\n const dock = layout !== 'page'\n const { conversations, selectedId, deselect } = useConversationsStore((s) => s)\n // A tela se atualiza sozinha: mesma campainha que o aviso global escuta.\n useCaixaAoVivo()\n // xl+ shows the contact panel inline (three panes); below that it's an\n // on-demand slide-over so the list + thread keep room to breathe.\n const isWideViewport = useMediaQuery('(min-width: 1280px)')\n const isWidePanel = isWideViewport && !dock\n // The app's right rail (assistant) takes a fourth column; with it open the\n // contact panel turns three panes into slivers, so it yields and comes back\n // when the rail closes. Toggling it by hand is still the last word.\n const railOpen = useRightRailStore((s) => s.open)\n const [panelOpen, setPanelOpen] = React.useState(false)\n const [newOpen, setNewOpen] = React.useState(false)\n const selected = conversations.find((c) => c.id === selectedId) ?? null\n React.useEffect(() => { if (newSignal > 0) setNewOpen(true) }, [newSignal])\n\n // Open the panel by default only when it fits inline; collapse it otherwise.\n React.useEffect(() => {\n setPanelOpen(isWidePanel && !railOpen)\n }, [isWidePanel, railOpen])\n\n // Declared, not drawn: PageActions applies the role gate, gives the button\n // the same size every other list's primary has, and on a phone moves it to\n // the FAB in the thumb's corner instead of shrinking it to an icon squeezed\n // into the top bar.\n const newActions: PageAction[] = React.useMemo(() => [{\n id: 'new-conversation',\n label: t('conversations.list.new'),\n icon: SquarePen,\n intent: 'primary',\n // Starting a conversation creates a thread — the FAB is a \"+\".\n creates: true,\n testId: 'conversations-new',\n permission: { feature: 'conversations', action: 'create' },\n onSelect: () => setNewOpen(true),\n }], [t])\n\n return (\n <>\n {/* Outside the inbox row: with a header slot this portals and takes no\n space; without one it falls in as a block above the screen, rather\n than a column wedged between the list and the thread. */}\n {!dock && (\n <PageHeaderActions>\n <PageActions actions={newActions} />\n </PageHeaderActions>\n )}\n\n <NewConversationPanel open={newOpen} onOpenChange={setNewOpen} />\n\n <div className=\"relative flex h-full min-h-0 overflow-hidden bg-background\">\n {/* Conversation list — single-pane below lg (full width), fixed rail at lg+.\n Below lg it yields to the thread once a conversation is open. */}\n <ConversationList className={cn(\n layout === 'page' && (selected ? 'hidden lg:flex' : 'flex'),\n layout === 'dock' && (selected ? 'hidden' : 'flex lg:w-full border-r-0'),\n layout === 'dock-wide' && 'flex lg:w-[300px]',\n )} />\n\n {/* Thread — hidden below lg until a conversation is selected. */}\n {selected ? (\n <MessageThread\n selected={selected}\n panelOpen={panelOpen}\n onTogglePanel={() => setPanelOpen((v) => !v)}\n onBack={deselect}\n backAlways={layout === 'dock'}\n className=\"flex\"\n />\n ) : layout === 'dock' ? null : (\n <section className={cn('min-w-0 flex-1 flex-col items-center justify-center bg-muted/20 text-muted-foreground', dock ? 'flex' : 'hidden lg:flex')}>\n <MessageSquare className=\"h-9 w-9\" />\n <p className=\"mt-2 text-sm\">{t('conversations.empty.select')}</p>\n </section>\n )}\n\n {/* Contact panel — inline column at xl, slide-over overlay below xl. */}\n {selected && panelOpen && (\n <>\n <Button variant=\"bare\" size=\"bare\"\n className={cn('absolute inset-0 z-10 rounded-none bg-black/40', !dock && 'xl:hidden')}\n aria-label=\"Close details\"\n onClick={() => setPanelOpen(false)}\n />\n <ContactPanel\n contact={selected}\n onClose={() => setPanelOpen(false)}\n className={cn('absolute inset-y-0 right-0 z-20 w-[340px] max-w-[88%] shadow-2xl', !dock && 'xl:static xl:z-auto xl:w-[300px] xl:max-w-none xl:shadow-none')}\n />\n </>\n )}\n </div>\n </>\n )\n}\n"]}