@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.
- package/dist/{chunk-LJKLHGFX.js → ConversationsPage-BTRYZPM7.js} +129 -123
- package/dist/ConversationsPage-BTRYZPM7.js.map +1 -0
- package/dist/{ConversationsSettings-7UQYM26R.js → ConversationsSettings-Q3PGQMB3.js} +3 -3
- package/dist/{ConversationsSettings-7UQYM26R.js.map → ConversationsSettings-Q3PGQMB3.js.map} +1 -1
- package/dist/{chunk-3FZX3ZQ3.js → chunk-2JV6B366.js} +77 -76
- package/dist/chunk-2JV6B366.js.map +1 -0
- package/dist/chunk-X7BP2JH6.js +74 -0
- package/dist/chunk-X7BP2JH6.js.map +1 -0
- package/dist/components/InboxWatcher.d.ts +6 -15
- package/dist/components/InboxWatcher.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +122 -143
- package/dist/index.js.map +1 -1
- package/dist/integrations/evolution/connectorDef.d.ts +4 -0
- package/dist/integrations/evolution/connectorDef.d.ts.map +1 -0
- package/dist/views/ConversationList.d.ts.map +1 -1
- package/dist/views/WhatsAppConnectionFooter.d.ts +8 -0
- package/dist/views/WhatsAppConnectionFooter.d.ts.map +1 -0
- package/package.json +4 -4
- package/dist/ConversationsPage-4V4VLM4D.js +0 -47
- package/dist/ConversationsPage-4V4VLM4D.js.map +0 -1
- package/dist/chunk-3FZX3ZQ3.js.map +0 -1
- package/dist/chunk-LJKLHGFX.js.map +0 -1
- package/dist/components/ConversationsRailPanel.d.ts +0 -15
- package/dist/components/ConversationsRailPanel.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/ConversationsRailPanel.tsx","../src/components/InboxWatcher.tsx","../src/data/accents.ts","../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/views/dashboardWidgets.tsx","../src/lib/onboarding.ts","../src/integrations/tyxter/data.ts","../src/data/payment-preflight.ts","../src/integrations/tyxter/connectorDef.tsx","../src/settings/v1-settings.ts","../src/data/campaigns.ts","../src/index.ts"],"names":["store","React","useRightRailStore","jsxs","Button","adminNavigateTo","jsx","client","getSupabaseClientOptional","useEffect","useMemo","useTranslation","invoke","tenant","ExternalLink","useState","useActiveTenantId","useRef","useCallback","tl","getActiveTenantId"],"mappings":"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","file":"index.js","sourcesContent":["import * as React from 'react'\nimport { Button } from '@fayz-ai/ui'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { CheckCircle2, ExternalLink, SquarePen } from 'lucide-react'\nimport { tl, useTranslation } from '@fayz-ai/core'\nimport { adminNavigateTo, useRightRailMenu, useRightRailStore } from '@fayz-ai/admin'\nimport { ConversationsContextProvider, type ResolvedConversationsConfig } from '../context'\nimport type { ConversationsUIState } from '../store'\nimport { InboxView } from '../views/InboxView'\nimport { useChannelConnections } from '../data/channel-connections'\n\nconst CONNECTORS_ROUTE = '/settings/conversations/connectors'\n// Wide enough for the list and the thread side by side.\nconst SPLIT_AT = 720\n\n/**\n * Conversas in the right column, beside the assistant: answering a customer is\n * work that has to stay open while the person checks an order or the agenda.\n * The column is narrow, so list and thread take turns; dragged wide, they sit\n * side by side.\n */\nexport function ConversationsRailPanel({ store, config }: {\n store: StoreApi<ConversationsUIState>\n config?: ResolvedConversationsConfig\n}) {\n const t = useTranslation()\n const ref = React.useRef<HTMLDivElement>(null)\n const [width, setWidth] = React.useState(0)\n const [newSignal, setNewSignal] = React.useState(0)\n const connected = useChannelConnections()\n const closeRail = useRightRailStore((s) => s.close)\n const wide = width >= SPLIT_AT\n\n React.useLayoutEffect(() => {\n const el = ref.current\n if (!el) return\n const ro = new ResizeObserver(([e]) => setWidth(e!.contentRect.width))\n ro.observe(el)\n return () => ro.disconnect()\n }, [])\n\n // Narrow starts on the list: landing inside someone's thread (and marking it\n // read) is not what a glance at the inbox asks for.\n React.useEffect(() => {\n const narrow = (ref.current?.getBoundingClientRect().width ?? 0) < SPLIT_AT\n if (narrow) store.getState().deselect()\n void store.getState().load({ autoSelect: !narrow })\n }, [store])\n\n const go = (route: string) => { closeRail(); adminNavigateTo(route) }\n\n useRightRailMenu([\n { id: 'new', label: t('conversations.list.new'), icon: SquarePen, onSelect: () => setNewSignal((n) => n + 1) },\n { id: 'full', label: tl('Open full screen', 'Abrir em tela cheia'), icon: ExternalLink, onSelect: () => go('/conversations') },\n ])\n\n return (\n <div ref={ref} className=\"flex h-full min-h-0 flex-col\">\n <div className=\"min-h-0 flex-1\">\n <ConversationsContextProvider store={store} config={config}>\n <InboxView layout={wide ? 'dock-wide' : 'dock'} newSignal={newSignal} />\n </ConversationsContextProvider>\n </div>\n <div className=\"shrink-0 border-t border-border p-3\">\n {connected === undefined ? (\n <div className=\"h-10\" aria-hidden />\n ) : connected.whatsapp ? (\n <Button variant=\"bare\" size=\"bare\" type=\"button\" onClick={() => go(CONNECTORS_ROUTE)}\n className=\"font-normal whitespace-normal justify-start fz-tap flex h-10 w-full items-center gap-2 rounded-button px-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground\">\n <CheckCircle2 className=\"h-4 w-4 text-[#25D366]\" aria-hidden />\n <span className=\"min-w-0 flex-1 truncate text-left\">{tl('WhatsApp connected', 'WhatsApp conectado')}</span>\n <span className=\"text-xs text-primary\">{tl('Manage', 'Gerenciar')}</span>\n </Button>\n ) : (\n <Button variant=\"bare\" size=\"bare\" type=\"button\" onClick={() => go(CONNECTORS_ROUTE)} data-testid=\"inbox-connect-whatsapp\"\n className=\"font-normal whitespace-normal fz-tap flex h-11 w-full items-center justify-center gap-2 rounded-button bg-[#25D366] text-sm font-semibold text-white shadow-sm transition-colors hover:bg-[#1EBE5A] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#25D366] focus-visible:ring-offset-2\">\n <WhatsAppMark className=\"h-[18px] w-[18px]\" />\n {tl('Connect WhatsApp', 'Conectar WhatsApp')}\n </Button>\n )}\n </div>\n </div>\n )\n}\n\n/** The WhatsApp glyph — lucide has none, and a generic bubble on a green\n * button reads as \"chat\", not as the channel being connected. */\nfunction WhatsAppMark({ className }: { className?: string }) {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className={className} aria-hidden>\n <path d=\"M17.47 14.38c-.3-.15-1.76-.87-2.03-.97-.27-.1-.47-.15-.67.15-.2.3-.77.96-.94 1.16-.17.2-.35.22-.65.07-.3-.15-1.26-.46-2.4-1.48-.89-.79-1.49-1.77-1.66-2.07-.17-.3-.02-.46.13-.61.13-.13.3-.35.45-.52.15-.17.2-.3.3-.5.1-.2.05-.37-.02-.52-.08-.15-.67-1.61-.92-2.2-.24-.58-.49-.5-.67-.51h-.57c-.2 0-.52.07-.79.37-.27.3-1.04 1.02-1.04 2.48s1.07 2.88 1.21 3.08c.15.2 2.1 3.2 5.08 4.49.71.31 1.26.49 1.69.63.71.22 1.36.19 1.87.12.57-.09 1.76-.72 2.01-1.41.25-.7.25-1.29.17-1.41-.07-.13-.27-.2-.57-.35zM12.05 21.5h-.01a9.4 9.4 0 0 1-4.8-1.32l-.34-.2-3.56.93.95-3.47-.22-.36a9.4 9.4 0 0 1-1.44-5.02c0-5.2 4.23-9.43 9.43-9.43 2.52 0 4.89.98 6.67 2.77a9.37 9.37 0 0 1 2.76 6.67c0 5.2-4.23 9.43-9.44 9.43zm8.03-17.46A11.3 11.3 0 0 0 12.05.72C5.79.72.7 5.81.7 12.07c0 2 .52 3.95 1.52 5.67L.6 23.6l6-1.57a11.32 11.32 0 0 0 5.44 1.39h.01c6.26 0 11.35-5.1 11.35-11.35 0-3.03-1.18-5.88-3.32-8.03z\" />\n </svg>\n )\n}\n","import * as React from 'react'\nimport { MessageCircle } from 'lucide-react'\nimport { getSupabaseClientOptional, useActiveTenantId } from '@fayz-ai/core'\nimport { adminNavigateTo, notifySystem, playChime, requestNotificationPermission, useAdminPath, useRightRailPanel, useRightRailStore, useWidgetSurface } from '@fayz-ai/admin'\nimport { Button } from '@fayz-ai/ui'\n\nimport type { StoreApi } from 'zustand/vanilla'\nimport type { ResolvedConversationsConfig } from '../context'\nimport type { ConversationsUIState } from '../store'\nimport { ConversationsRailPanel } from './ConversationsRailPanel'\nimport { T } from '../data/tables'\nimport { assinarChegada } from '../lib/campainha'\nimport { isWaitingOnUs } from '../types'\n\n// ---------------------------------------------------------------------------\n// A CAIXA DE ENTRADA, na faixa do aplicativo: um ícone e a conta do que espera\n// resposta. Clica e abre a caixa.\n//\n// Era uma linha do rail. Conversas não é um módulo como o Financeiro ou o CRM:\n// é um estado — \"tem gente esperando\" — e estado se lê de canto de olho, do\n// mesmo canto onde já estão o sino e os interruptores da casa. No rail ele\n// ocupava uma linha inteira ao lado de destinos, e a conta que lhe importa\n// ficava escondida atrás de um menu que recolhe.\n//\n// O componente é o MESMO vigia de antes: a chegada de uma mensagem tem de ser\n// percebida por quem NÃO está olhando para a caixa — que é o caso normal: o\n// operador está no funil, na ficha de um lead, no financeiro.\n//\n// ── por que ele mora num widget da topbar ──────────────────────────────\n//\n// `shell.topbar.end` é a única zona global que o AdminShell renderiza FORA do\n// switch de rota. Um hook dentro da tela de Conversas só vive enquanto a tela\n// vive: sairia da caixa e o alerta morreria junto — exatamente nas horas em que\n// ele serve para alguma coisa.\n//\n// ── o som é gerado, não é um arquivo ───────────────────────────────────\n//\n// Um .mp3 no pacote significa um binário no bundle, um caminho de asset que\n// muda entre apps e um 404 silencioso no dia em que o caminho muda. Dois\n// osciladores de WebAudio dão uma nota de meio segundo e não dependem de nada.\n//\n// E ele só toca depois do PRIMEIRO GESTO da pessoa na página: navegador nenhum\n// deixa tocar áudio antes disso, e insistir enche o console de erro. Antes do\n// gesto, o badge sozinho — que é visual e não pede permissão.\n//\n// ── e por que ele conta sozinho em vez de ler o store ───────────────────\n//\n// O store da caixa vive dentro do contexto do plugin, que envolve as TELAS\n// dele — não a topbar. O vigia está fora desse contexto de propósito (é o que\n// o mantém vivo ao navegar), então faz a própria leitura: barata, porque pede\n// só as três colunas que decidem a conta.\n// ---------------------------------------------------------------------------\n\n// The chime, the permission prompt and the system notification live in\n// @fayz-ai/admin (lib/attention.ts) since the shell's bell needs the same three;\n// the rules that shaped them were written here first.\nconst tocar = playChime\nconst pedirPermissao = requestNotificationPermission\nconst avisarNoSistema = (titulo: string, corpo: string, tag: string) => notifySystem(titulo, corpo, tag)\n\nconst RAIL_ID = 'conversations'\n\nexport function InboxWatcher({ label, route = '/conversations', store, config, inHeader }: {\n /** O nome da caixa. Só chega ao olho no `title`/`aria-label` do botão e no\n * título da notificação do sistema: na faixa o ícone basta, e um rótulo por\n * extenso ao lado de cada controle deste canto encheria a linha. */\n label: string\n route?: string\n /** With the inbox store the button opens the floating inbox; without it,\n * it goes to the inbox page as before. */\n store?: StoreApi<ConversationsUIState>\n config?: ResolvedConversationsConfig\n /** Mounted as a header control: icon only, never the labelled menu row. */\n inHeader?: boolean\n}) {\n // With the store, Conversas opens in the right column beside the assistant\n // instead of taking the page.\n const Panel = React.useMemo(() => {\n if (!store) return null\n const C: React.FC = () => React.createElement(ConversationsRailPanel, { store, config })\n C.displayName = 'ConversationsRailPanel'\n return C\n }, [store, config])\n const railOpen = useRightRailStore((s) => s.open && s.active === RAIL_ID)\n const togglePanel = useRightRailStore((s) => s.togglePanel)\n const tenantId = useActiveTenantId()\n const path = useAdminPath()\n const [naoLidas, setNaoLidas] = React.useState(0)\n const podeTocar = React.useRef(false)\n\n // O primeiro gesto libera o áudio. `once` em três eventos porque o gesto que\n // conta varia: rato no desktop, toque no telefone, tecla em quem navega pelo\n // teclado.\n React.useEffect(() => {\n const liberar = () => {\n podeTocar.current = true\n // O mesmo gesto que libera o som serve para pedir a permissão: é o único\n // instante em que o navegador aceita o pedido, e gastar dois gestos para\n // duas permissões seria gastar o segundo à toa.\n void pedirPermissao()\n }\n for (const ev of ['pointerdown', 'keydown', 'touchstart']) {\n window.addEventListener(ev, liberar, { once: true, passive: true })\n }\n return () => { for (const ev of ['pointerdown', 'keydown', 'touchstart']) window.removeEventListener(ev, liberar) }\n }, [])\n\n const contar = React.useCallback(async () => {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return\n // Só o que decide `isWaitingOnUs`: estado, direção da última e a conta.\n // Pedir a conversa inteira aqui seria carregar a caixa toda a cada\n // mensagem, em toda tela do app.\n const { data } = await supabase\n .from(T.conversations)\n .select('id, status, last_message_direction, unread_count')\n .eq('status', 'open')\n if (!data) return\n const n = (data as any[]).filter((r) => isWaitingOnUs({\n status: r.status,\n lastMessageDirection: r.last_message_direction ?? undefined,\n unreadCount: r.unread_count ?? 0,\n } as any)).length\n setNaoLidas(n)\n }, [])\n\n React.useEffect(() => { void contar() }, [contar])\n\n // UMA assinatura, partilhada com a caixa aberta.\n //\n // Dois canais com o mesmo tópico no mesmo cliente não recebem os dois: um\n // vence. Em produção quem venceu foi a tela — a mensagem aparecia sozinha e\n // a notificação do sistema não saía, sem erro nenhum. Cada um testado em\n // separado passava; juntos, um emudecia.\n React.useEffect(() => {\n if (!tenantId) return\n return assinarChegada(tenantId, ({ conversationId }) => {\n void contar()\n if (podeTocar.current) tocar()\n void (async () => {\n const supabase = getSupabaseClientOptional() as any\n let titulo = label\n let corpo = ''\n if (conversationId && supabase) {\n // Leitura normal: RLS aplicada, cabeçalho da conta presente. A\n // campainha traz só o id justamente para o conteúdo vir por aqui.\n const { data } = await supabase\n .from(T.conversations)\n .select('contact_name, last_message_preview')\n .eq('id', conversationId)\n .maybeSingle()\n titulo = (data as any)?.contact_name || label\n corpo = String((data as any)?.last_message_preview || '').replace(/\\s+/g, ' ').slice(0, 140)\n }\n avisarNoSistema(titulo, corpo, String(conversationId ?? 'inbox'))\n })()\n })\n }, [contar, tenantId, label])\n\n useRightRailPanel(React.useMemo(() => (Panel ? {\n id: RAIL_ID,\n label,\n icon: MessageCircle,\n order: 12,\n badge: { count: naoLidas, tone: 'destructive' as const },\n Component: Panel,\n } : null), [Panel, label, naoLidas]))\n\n const naPagina = path === route || path.startsWith(`${route}/`)\n const aberta = naPagina || railOpen\n // `rail` is a column with room for the name — the phone's quick menu.\n // Header controls sit outside any widget surface, whose default is `rail`.\n const surface = useWidgetSurface()\n const named = !inHeader && surface === 'rail'\n\n return (\n <Button variant=\"bare\" size=\"bare\"\n type=\"button\"\n onClick={() => (Panel && !naPagina ? togglePanel(RAIL_ID) : adminNavigateTo(route))}\n aria-expanded={Panel ? railOpen : undefined}\n aria-label={naoLidas > 0 ? `${label} (${naoLidas})` : label}\n title={label}\n aria-current={aberta ? 'page' : undefined}\n className={`fz-tap relative inline-flex shrink-0 items-center rounded-button transition-colors hover:bg-accent ${\n named ? 'w-full gap-3 px-2.5 py-2.5' : 'justify-center p-2'\n } ${aberta ? 'text-foreground' : 'text-muted-foreground hover:text-foreground'}`}\n >\n <MessageCircle className=\"h-4 w-4 shrink-0\" />\n {named && <span className=\"min-w-0 flex-1 truncate text-left\">{label}</span>}\n {naoLidas > 0 && (\n <span className=\"absolute -right-0.5 -top-0.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-destructive px-1 text-[10px] font-medium leading-none text-destructive-foreground tabular-nums\">\n {naoLidas > 9 ? '9+' : naoLidas}\n </span>\n )}\n </Button>\n )\n}\n","import type { Channel } from '../types'\n\n// Solid brand hex per channel — mirrors CHANNEL_ACCENT in ../channel.ts but\n// React-free so the data providers can stamp a sensible avatar accent on new\n// conversations without importing the icon layer.\nexport const CHANNEL_ACCENT_HEX: Record<Channel, string> = {\n whatsapp: '#22c55e',\n sms: '#6366f1',\n instagram: '#ec4899',\n email: '#0ea5e9',\n webchat: '#f59e0b',\n}\n","import type { ConversationsProvider } from './types'\nimport { CHANNEL_ACCENT_HEX } from './accents'\nimport type {\n Conversation,\n Message,\n ListConversationsQuery,\n SendMessageInput,\n CreateConversationInput,\n ConversationStatus,\n} from '../types'\n\n// Deterministic relative timestamps (no Date.now at module init for stable seeds).\nfunction minutesAgo(base: number, mins: number): string {\n return new Date(base - mins * 60_000).toISOString()\n}\n\nfunction seed(): { conversations: Conversation[]; messages: Message[] } {\n const base = new Date('2026-06-16T14:00:00Z').getTime()\n\n const conversations: Conversation[] = [\n {\n id: 'c1', contactName: 'Marina Alves', contactHandle: '+55 11 99876-1020', channel: 'whatsapp',\n lastMessagePreview: 'Perfect, can we book for Friday at 3pm?', lastMessageAt: minutesAgo(base, 4),\n lastMessageDirection: 'inbound',\n unreadCount: 2, status: 'open', assignedTo: 'You', accent: '#22c55e', tags: ['Hot lead'],\n location: 'São Paulo, BR', note: 'Referred by Instagram ad — interested in full color + cut.',\n },\n {\n id: 'c2', contactName: 'Jordan Pierce', contactHandle: '+1 (415) 555-0142', channel: 'sms',\n lastMessagePreview: 'Got it — sending the deposit now.', lastMessageAt: minutesAgo(base, 22),\n lastMessageDirection: 'inbound',\n unreadCount: 0, status: 'open', assignedTo: 'You', accent: '#6366f1', tags: ['Customer'],\n location: 'San Francisco, US',\n },\n {\n id: 'c3', contactName: '@thehairloft', contactHandle: 'thehairloft', channel: 'instagram',\n lastMessagePreview: 'Do you offer balayage on weekends?', lastMessageAt: minutesAgo(base, 51),\n lastMessageDirection: 'inbound',\n unreadCount: 1, status: 'open', accent: '#ec4899', tags: ['New'],\n },\n {\n id: 'c4', contactName: 'David Whitman', contactHandle: 'david@whitman.co', channel: 'email',\n lastMessagePreview: 'Re: Proposal — looks great, one question on pricing…', lastMessageAt: minutesAgo(base, 95),\n // Read, never answered — zero unread and a customer still waiting. The\n // exact case `unreadCount` alone gets wrong.\n lastMessageDirection: 'inbound',\n unreadCount: 0, status: 'open', assignedTo: 'Sofia', accent: '#0ea5e9', tags: ['Proposal'],\n location: 'Austin, US', note: 'Evaluating the retainer tier. Decision expected this week.',\n },\n {\n id: 'c5', contactName: 'Website visitor', contactHandle: 'live chat · acme.com', channel: 'webchat',\n lastMessagePreview: 'Is anyone available to chat?', lastMessageAt: minutesAgo(base, 140),\n lastMessageDirection: 'inbound',\n unreadCount: 0, status: 'snoozed', accent: '#f59e0b', tags: [],\n },\n {\n id: 'c6', contactName: 'Priya Nair', contactHandle: '+44 7700 900123', channel: 'whatsapp',\n lastMessagePreview: 'Thank you! See you next week 🙌', lastMessageAt: minutesAgo(base, 1440),\n lastMessageDirection: 'outbound',\n unreadCount: 0, status: 'closed', assignedTo: 'You', accent: '#14b8a6', tags: ['Customer'],\n location: 'London, UK',\n },\n ]\n\n const messages: Message[] = [\n msg('m1', 'c1', 'whatsapp', 'inbound', 'Hi! I saw your ad — do you have availability this week?', 'Marina Alves', minutesAgo(base, 18)),\n msg('m2', 'c1', 'whatsapp', 'outbound', 'Hi Marina! Yes, we do. What service are you interested in?', 'You', minutesAgo(base, 15)),\n msg('m3', 'c1', 'whatsapp', 'inbound', 'A full color + cut.', 'Marina Alves', minutesAgo(base, 9)),\n msg('m4', 'c1', 'whatsapp', 'inbound', 'Perfect, can we book for Friday at 3pm?', 'Marina Alves', minutesAgo(base, 4)),\n\n msg('m5', 'c2', 'sms', 'outbound', 'Your appointment is confirmed for tomorrow at 10am.', 'You', minutesAgo(base, 40)),\n msg('m6', 'c2', 'sms', 'inbound', 'Got it — sending the deposit now.', 'Jordan Pierce', minutesAgo(base, 22)),\n\n msg('m7', 'c3', 'instagram', 'inbound', 'Do you offer balayage on weekends?', '@thehairloft', minutesAgo(base, 51)),\n\n msg('m8', 'c4', 'email', 'inbound', 'Re: Proposal — looks great, one question on pricing for the retainer tier.', 'David Whitman', minutesAgo(base, 95)),\n msg('m9', 'c4', 'email', 'outbound', 'Happy to walk you through it — are you free for a quick call tomorrow?', 'Sofia', minutesAgo(base, 80)),\n\n msg('m10', 'c5', 'webchat', 'inbound', 'Is anyone available to chat?', 'Website visitor', minutesAgo(base, 140)),\n\n msg('m11', 'c6', 'whatsapp', 'outbound', 'You are all set for next Tuesday. Anything else?', 'You', minutesAgo(base, 1500)),\n msg('m12', 'c6', 'whatsapp', 'inbound', 'Thank you! See you next week 🙌', 'Priya Nair', minutesAgo(base, 1440)),\n ]\n\n return { conversations, messages }\n}\n\nfunction msg(\n id: string, conversationId: string, channel: Message['channel'],\n direction: Message['direction'], body: string, author: string, at: string,\n): Message {\n return { id, conversationId, channel, direction, body, author, at }\n}\n\nexport interface MockConversationsConfig {\n /** Tenant id (value or getter) used to namespace the localStorage snapshot. */\n tenantId?: string | (() => string | undefined)\n /** Display name stamped as the author of outbound messages. */\n selfAuthor?: string\n}\n\ninterface Snapshot {\n conversations: Conversation[]\n messages: Message[]\n counter: number\n}\n\n// ---------------------------------------------------------------------------\n// In-memory mock inbox with best-effort localStorage persistence, so a browser\n// reload keeps whatever the demo created/sent within the session. The store is\n// namespaced per tenant; SSR / no-window environments degrade to pure memory.\n// ---------------------------------------------------------------------------\nexport function createMockConversationsProvider(\n config?: MockConversationsConfig,\n): ConversationsProvider {\n const selfAuthor = config?.selfAuthor ?? 'You'\n\n function resolveTenant(): string {\n const raw = typeof config?.tenantId === 'function' ? config.tenantId() : config?.tenantId\n return raw || 'default'\n }\n\n const storageKey = () => `saas:mock:conversations:${resolveTenant()}`\n\n function hasStorage(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.localStorage\n } catch {\n return false\n }\n }\n\n function load(): Snapshot {\n if (hasStorage()) {\n try {\n const raw = window.localStorage.getItem(storageKey())\n if (raw) {\n const parsed = JSON.parse(raw) as Snapshot\n if (Array.isArray(parsed.conversations) && Array.isArray(parsed.messages)) {\n return {\n conversations: parsed.conversations,\n messages: parsed.messages,\n counter: parsed.counter ?? 100,\n }\n }\n }\n } catch {\n // Corrupt snapshot — fall through to a fresh seed.\n }\n }\n const seeded = seed()\n return { conversations: seeded.conversations, messages: seeded.messages, counter: 100 }\n }\n\n const state = load()\n\n function persist(): void {\n if (!hasStorage()) return\n try {\n window.localStorage.setItem(\n storageKey(),\n JSON.stringify({\n conversations: state.conversations,\n messages: state.messages,\n counter: state.counter,\n } satisfies Snapshot),\n )\n } catch {\n // Quota / privacy mode — keep working in memory only.\n }\n }\n\n // Persist the initial seed so a first reload is already stable.\n persist()\n\n return {\n async listConversations(query?: ListConversationsQuery): Promise<Conversation[]> {\n let list = [...state.conversations]\n if (query?.channel && query.channel !== 'all') list = list.filter((c) => c.channel === query.channel)\n if (query?.status && query.status !== 'all') list = list.filter((c) => c.status === query.status)\n if (query?.search) {\n const q = query.search.toLowerCase()\n list = list.filter(\n (c) => c.contactName.toLowerCase().includes(q) || c.lastMessagePreview.toLowerCase().includes(q),\n )\n }\n return list.sort((a, b) => b.lastMessageAt.localeCompare(a.lastMessageAt))\n },\n\n async getMessages(conversationId: string): Promise<Message[]> {\n return state.messages\n .filter((m) => m.conversationId === conversationId)\n .sort((a, b) => a.at.localeCompare(b.at))\n },\n\n async createConversation(input: CreateConversationInput): Promise<Conversation> {\n const now = new Date().toISOString()\n const firstMessage = input.firstMessage?.trim()\n const id = `c${++state.counter}`\n const conversation: Conversation = {\n id,\n contactName: input.contactName.trim(),\n contactPersonId: input.contactPersonId,\n contactHandle: input.contactHandle?.trim() ?? '',\n channel: input.channel,\n lastMessagePreview: firstMessage ?? '',\n lastMessageAt: now,\n // A thread the house opened is not waiting on the house. Left undefined\n // when there is no first message: nobody has spoken, so there is no\n // last speaker to name, and `isWaitingOnUs` falls back to unread (0).\n lastMessageDirection: firstMessage ? 'outbound' : undefined,\n unreadCount: 0,\n status: 'open',\n assignedTo: selfAuthor,\n accent: CHANNEL_ACCENT_HEX[input.channel],\n tags: [],\n note: input.note?.trim() || undefined,\n }\n state.conversations.unshift(conversation)\n if (firstMessage) {\n state.messages.push({\n id: `m${++state.counter}`,\n conversationId: id,\n channel: input.channel,\n direction: 'outbound',\n body: firstMessage,\n author: selfAuthor,\n at: now,\n })\n }\n persist()\n return conversation\n },\n\n async sendMessage(input: SendMessageInput): Promise<Message> {\n const conv = state.conversations.find((c) => c.id === input.conversationId)\n const created: Message = {\n id: `m${++state.counter}`,\n conversationId: input.conversationId,\n channel: conv?.channel ?? 'sms',\n direction: 'outbound',\n body: input.body,\n author: selfAuthor,\n at: new Date().toISOString(),\n }\n state.messages.push(created)\n if (conv) {\n conv.lastMessagePreview = input.body\n conv.lastMessageAt = created.at\n conv.lastMessageDirection = 'outbound'\n conv.unreadCount = 0\n if (conv.status === 'closed') conv.status = 'open'\n }\n persist()\n return created\n },\n\n async markRead(conversationId: string): Promise<void> {\n const conv = state.conversations.find((c) => c.id === conversationId)\n if (conv && conv.unreadCount !== 0) {\n conv.unreadCount = 0\n persist()\n }\n },\n\n async setStatus(conversationId: string, status: ConversationStatus): Promise<Conversation> {\n const conv = state.conversations.find((c) => c.id === conversationId)\n if (!conv) throw new Error('Conversation not found')\n conv.status = status\n persist()\n return conv\n },\n }\n}\n","import { getSupabaseClientOptional } from '@fayz-ai/core'\nimport type { ConversationsProvider } from './types'\nimport { T } from './tables'\nimport { CHANNEL_ACCENT_HEX } from './accents'\nimport type {\n Conversation,\n Message,\n ListConversationsQuery,\n SendMessageInput,\n CreateConversationInput,\n ConversationStatus,\n MessageDirection,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// Supabase-backed conversations provider — reads/writes the project's\n// `conversations` + `conversation_messages` tables (tenant-scoped via RLS +\n// an explicit tenant filter from the active-org context). Mirrors the inline\n// client-casting style of @fayz-ai/core's createSupabaseProvider; the global\n// client is `unknown`-typed so each call narrows the shape it needs.\n//\n// Real channel connectors (Twilio, WhatsApp Cloud, Meta, IMAP) deliver inbound\n// rows into these tables out-of-band; this provider is the read/compose surface.\n// ---------------------------------------------------------------------------\n\nexport interface SupabaseConversationsConfig {\n /** Supabase client; defaults to the global one registered by createFayzApp. */\n supabaseClient?: unknown\n /** Active tenant id (value or getter) used to scope reads and stamp writes. */\n tenantId?: string | (() => string | undefined)\n /** Display name stamped as the author of outbound messages. */\n selfAuthor?: string\n}\n\ntype Row = Record<string, unknown>\n\nfunction mapConversation(r: Row): Conversation {\n return {\n id: String(r.id),\n contactName: (r.contact_name as string) ?? '',\n contactPersonId: (r.contact_person_id as string | null) ?? undefined,\n contactHandle: (r.contact_handle as string) ?? '',\n channel: (r.channel as Conversation['channel']) ?? 'sms',\n lastMessagePreview: (r.last_message_preview as string) ?? '',\n lastMessageAt: (r.last_message_at as string) ?? '',\n // Kept current by the trigger in migration 001, never written from here:\n // the column has one writer on purpose (last_message_preview/at have five,\n // which is the mistake this one was not going to repeat).\n lastMessageDirection: (r.last_message_direction as MessageDirection | null) ?? undefined,\n unreadCount: Number(r.unread_count ?? 0),\n acknowledgedAt: (r.acknowledged_at as string | null) ?? null,\n status: (r.status as ConversationStatus) ?? 'open',\n assignedTo: (r.assigned_to as string | null) ?? undefined,\n // Presentes só quando a leitura veio da view. Na escrita (que volta da\n // tabela) ficam nulos, e a lista recarrega logo a seguir.\n leadOwnerId: (r.lead_owner_id as string | null) ?? undefined,\n leadOwnerName: (r.lead_owner_name as string | null) ?? undefined,\n accent: (r.accent as string) ?? '#6366f1',\n tags: (r.tags as string[] | null) ?? [],\n location: (r.location as string | null) ?? undefined,\n note: (r.note as string | null) ?? undefined,\n }\n}\n\nfunction mapMessage(r: Row): Message {\n return {\n id: String(r.id),\n conversationId: String(r.conversation_id),\n channel: (r.channel as Message['channel']) ?? 'sms',\n direction: (r.direction as Message['direction']) ?? 'inbound',\n body: (r.body as string) ?? '',\n at: (r.at as string) ?? '',\n author: (r.author as string) ?? '',\n deliveryStatus: (r.delivery_status as string) ?? null,\n providerMessageId: (r.provider_message_id as string) ?? null,\n // NULL stays null rather than defaulting to 'text'. A row written before\n // migration 012 genuinely does not know what it was, and the rows that most\n // need saying so are the empty ones that a 'text' default would call fine.\n messageType: (r.message_type as Message['messageType']) ?? null,\n payload: (r.payload as Message['payload']) ?? null,\n mediaPath: (r.media_path as string) ?? null,\n }\n}\n\nexport function createSupabaseConversationsProvider(\n config?: SupabaseConversationsConfig,\n): ConversationsProvider {\n /** O que o provedor chama de status, no vocabulário que a nossa coluna aceita.\n * Um valor desconhecido vira `sent`: a mensagem saiu, e inventar um estado\n * que o CHECK recusa transforma um envio bem-sucedido num erro. */\nconst DELIVERY = new Set(['queued','sent','delivered','read','failed','expired','delivery_timeout','cancelled','opted_out'])\nfunction mapDeliveryStatus(raw: unknown): string {\n const v = String(raw ?? '').toLowerCase()\n if (v === 'accepted' || v === 'received') return 'sent'\n return DELIVERY.has(v) ? v : 'sent'\n}\n\nconst selfAuthor = config?.selfAuthor ?? 'You'\n\n function resolveTenantId(): string | undefined {\n if (!config?.tenantId) return undefined\n return typeof config.tenantId === 'function' ? config.tenantId() : config.tenantId\n }\n\n function client(): { from: (t: string) => Row } {\n const supabase = (config?.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 return supabase\n }\n\n return {\n async listConversations(query?: ListConversationsQuery): Promise<Conversation[]> {\n // A VIEW, não a tabela: ela traz o dono do lead junto, e sem isso a\n // caixa teria de resolver o de-para por conversa no cliente.\n let q = (client().from(T.conversationsView) as { select: (s: string) => Row }).select('*')\n\n const tenantId = resolveTenantId()\n if (tenantId) q = (q as { eq: (c: string, v: string) => Row }).eq('tenant_id', tenantId)\n if (query?.channel && query.channel !== 'all') {\n q = (q as { eq: (c: string, v: string) => Row }).eq('channel', query.channel)\n }\n if (query?.status && query.status !== 'all') {\n q = (q as { eq: (c: string, v: string) => Row }).eq('status', query.status)\n }\n if (query?.leadOwnerId === 'none') {\n q = (q as { is: (c: string, v: null) => Row }).is('lead_owner_id', null)\n } else if (query?.leadOwnerId) {\n q = (q as { eq: (c: string, v: string) => Row }).eq('lead_owner_id', query.leadOwnerId)\n }\n if (query?.search) {\n const term = `%${query.search}%`\n q = (q as { or: (c: string) => Row }).or(\n `contact_name.ilike.${term},last_message_preview.ilike.${term}`,\n )\n }\n q = (q as { order: (c: string, o: unknown) => Row }).order('last_message_at', {\n ascending: false,\n })\n\n const { data, error } = (await q) as { data: Row[] | null; error: unknown }\n if (error) throw error\n return (data ?? []).map(mapConversation)\n },\n\n async getMessages(conversationId: string): Promise<Message[]> {\n const selected = (\n client().from(T.messages) as { select: (s: string) => Row }\n ).select('*')\n const filtered = (selected as { eq: (c: string, v: string) => Row }).eq(\n 'conversation_id',\n conversationId,\n )\n const ordered = (filtered as { order: (c: string, o: unknown) => Row }).order('at', {\n ascending: true,\n })\n const { data, error } = (await ordered) as { data: Row[] | null; error: unknown }\n if (error) throw error\n return (data ?? []).map(mapMessage)\n },\n\n async createConversation(input: CreateConversationInput): Promise<Conversation> {\n const tenantId = resolveTenantId()\n // Insert with a null tenant_id fails the plg_conversations RLS WITH CHECK\n // (tenant_id ∈ user_tenant_ids()) with an opaque Postgres error. When the\n // active tenant hasn't resolved yet (bootstrap race), fail fast with an\n // actionable message the compose modal can surface via toast.\n if (!tenantId) {\n throw new Error('[plugin-conversations] Active tenant not resolved — cannot create conversation. Try again in a moment.')\n }\n const now = new Date().toISOString()\n const firstMessage = input.firstMessage?.trim()\n\n const convRow: Row = {\n contact_name: input.contactName.trim(),\n // Only written when the picker resolved a real person — an app that\n // hasn't run migration 002 yet would reject an unknown column, and\n // omitting it keeps the free-text path working there.\n ...(input.contactPersonId ? { contact_person_id: input.contactPersonId } : {}),\n contact_handle: input.contactHandle?.trim() || null,\n channel: input.channel,\n last_message_preview: firstMessage || null,\n last_message_at: now,\n unread_count: 0,\n status: 'open',\n assigned_to: selfAuthor,\n accent: CHANNEL_ACCENT_HEX[input.channel],\n tags: [],\n note: input.note?.trim() || null,\n }\n if (tenantId) convRow.tenant_id = tenantId\n\n const { data: created, error } = (await (\n (client().from(T.conversations) as { insert: (r: Row) => Row }).insert(convRow) as {\n select: () => { single: () => Promise<{ data: Row | null; error: unknown }> }\n }\n )\n .select()\n .single()) as { data: Row | null; error: unknown }\n if (error) throw error\n if (!created) throw new Error('Conversation not created')\n\n // Seed the thread with the first outbound message when provided.\n if (firstMessage) {\n const msgRow: Row = {\n conversation_id: String(created.id),\n channel: input.channel,\n direction: 'outbound',\n body: firstMessage,\n author: selfAuthor,\n at: now,\n }\n if (tenantId) msgRow.tenant_id = tenantId\n await (client().from(T.messages) as { insert: (r: Row) => Promise<unknown> }).insert(msgRow)\n }\n\n return mapConversation(created)\n },\n\n async sendMessage(input: SendMessageInput): Promise<Message> {\n\n const tenantId = resolveTenantId()\n\n // Resolve the channel from the parent conversation so the message matches.\n const convSelected = (client().from(T.conversations) as { select: (s: string) => Row }).select(\n 'channel, contact_handle',\n )\n const convFiltered = (convSelected as { eq: (c: string, v: string) => Row }).eq(\n 'id',\n input.conversationId,\n )\n const { data: conv } = (await (\n convFiltered as { maybeSingle: () => Promise<{ data: Row | null }> }\n ).maybeSingle()) as { data: Row | null }\n const channel = (conv?.channel as Message['channel']) ?? 'sms'\n\n const at = new Date().toISOString()\n const row: Row = {\n conversation_id: input.conversationId,\n channel,\n direction: 'outbound',\n body: input.body,\n author: selfAuthor,\n at,\n }\n if (tenantId) row.tenant_id = tenantId\n\n const { data: created, error } = (await (\n (client().from(T.messages) as { insert: (r: Row) => Row }).insert(row) as {\n select: () => { single: () => Promise<{ data: Row | null; error: unknown }> }\n }\n )\n .select()\n .single()) as { data: Row | null; error: unknown }\n if (error) throw error\n\n // E AGORA A MENSAGEM SAI DE VERDADE.\n //\n // Até aqui `sendMessage` gravava a linha e terminava. A caixa mostrava a\n // mensagem enviada, o destinatário nunca recebia nada, e não havia erro\n // em lugar nenhum — duas mensagens ficaram meses paradas nesta tabela\n // antes de alguém perguntar por quê.\n //\n // O envio é DEPOIS da gravação, de propósito: se a entrega falhar, a\n // linha continua existindo com a falha registrada. O contrário — mandar\n // e só então gravar — perde a mensagem quando a gravação falha, e aí\n // ninguém sabe o que foi dito.\n //\n // A falha não é silenciosa: ela sobe. Quem chamou decide o que mostrar.\n // O que o envio devolveu, para o objeto RETORNADO carregar. A primeira\n // versão devolvia a linha capturada ANTES do envio: sem id do provedor e\n // sem status. A caixa então desenhava vermelho — \"sem id, não saiu\" — uma\n // mensagem que tinha acabado de ser entregue. O banco estava certo e a\n // tela mentia até o próximo recarregamento.\n let sentId: string | null = null\n let sentStatus: string | null = null\n\n if (channel === 'whatsapp') {\n const handle = String((conv as Row | null)?.contact_handle ?? '')\n try {\n const { data: out, error: sendErr } = await (client() as any).functions.invoke(\n 'conversations-provider',\n { body: { tenantId, action: 'send', to: handle, text: input.body } },\n )\n if (sendErr) {\n const detail = (await sendErr.context?.json?.().catch(() => null)) as { message?: string } | null\n throw new Error(detail?.message ?? sendErr.message)\n }\n if ((out as any)?.error) throw new Error((out as any).message ?? (out as any).error)\n sentId = (out as any)?.providerMessageId ?? null\n // `queued` é uma resposta, não uma falha: o provedor desta casa só é\n // alcançável da máquina dela, e a nuvem deixou a linha para o\n // disparador local. O balão fica cinza com o relógio até ele passar.\n sentStatus = (out as any)?.queued ? 'queued' : mapDeliveryStatus((out as any)?.status)\n if (created?.id) {\n await ((client().from(T.messages) as { update: (r: Row) => Row }).update({\n provider_message_id: sentId,\n // O provedor fala o dialeto dele. A Tyxter devolve `accepted`,\n // que NÃO existe no CHECK desta coluna — o update explodia, caía\n // no catch, e a mensagem era marcada como falha mesmo tendo\n // saído. Foi assim que \"opa\" apareceu verde e contou como erro.\n delivery_status: sentStatus,\n }) as { eq: (c: string, v: string) => Promise<unknown> }).eq('id', String(created.id))\n }\n } catch (err) {\n if (created?.id) {\n await ((client().from(T.messages) as { update: (r: Row) => Row }).update({\n delivery_status: 'failed',\n }) as { eq: (c: string, v: string) => Promise<unknown> }).eq('id', String(created.id))\n }\n throw err\n }\n }\n\n // Roll the parent conversation forward (preview / timestamp / unread / reopen).\n await (\n (client().from(T.conversations) as {\n update: (r: Row) => Row\n }).update({\n last_message_preview: input.body,\n last_message_at: at,\n unread_count: 0,\n status: 'open',\n }) as { eq: (c: string, v: string) => Promise<unknown> }\n ).eq('id', input.conversationId)\n\n return {\n ...mapMessage(created ?? row),\n providerMessageId: sentId,\n deliveryStatus: sentStatus,\n }\n },\n\n async markRead(conversationId: string): Promise<void> {\n const { error } = (await (\n (client().from(T.conversations) as { update: (r: Row) => Row }).update({\n unread_count: 0,\n // O instante é o que tira a bolinha. `unread_count` sozinho não\n // tirava — a fila olha a DIREÇÃO da última mensagem, e ela continua\n // sendo de entrada por mais que alguém leia.\n acknowledged_at: new Date().toISOString(),\n }) as { eq: (c: string, v: string) => Promise<{ error: unknown }> }\n ).eq('id', conversationId)) as { error: unknown }\n if (error) throw error\n },\n\n async setStatus(conversationId: string, status: ConversationStatus): Promise<Conversation> {\n const updated = (client().from(T.conversations) as { update: (r: Row) => Row }).update({\n status,\n })\n const filtered = (updated as { eq: (c: string, v: string) => Row }).eq('id', conversationId)\n const selected = (filtered as { select: () => Row }).select()\n const { data, error } = (await (\n selected as { single: () => Promise<{ data: Row | null; error: unknown }> }\n ).single()) as { data: Row | null; error: unknown }\n if (error) throw error\n if (!data) throw new Error('Conversation not found')\n return mapConversation(data)\n },\n }\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport type { ConversationsProvider } from './data/types'\nimport type {\n Conversation,\n Message,\n Channel,\n ConversationStatus,\n CreateConversationInput,\n} from './types'\n\n/** Quem, por onde, e como chamá-lo. Vem de outro módulo — hoje a ficha do lead\n * no CRM — que sabe a pessoa e não sabe nada sobre conversas. */\nexport interface OpenForPersonInput {\n /** `public.people` id. É por ele que a conversa é reconhecida; o telefone é\n * o desempate para threads antigas, criadas antes de haver vínculo. */\n personId?: string\n name: string\n handle: string\n channel: Channel\n}\n\n/** Só os dígitos. `+55 11 99999-0000` e `5511999990000` são o mesmo telefone, e\n * comparar como texto cru abriria uma segunda thread para a mesma pessoa. */\nfunction handleKey(h: string | undefined | null): string {\n const v = (h ?? '').trim()\n if (!v) return ''\n return /[@a-z]/i.test(v) ? v.toLowerCase() : v.replace(/\\D/g, '')\n}\n\nexport interface ConversationsUIState {\n conversations: Conversation[]\n messages: Message[]\n selectedId: string | null\n refreshMessages: () => Promise<void>\n channelFilter: Channel | 'all'\n /** Recorte por DONO DO LEAD. `'none'` é a fila sem dono. */\n leadOwnerFilter?: string | 'none'\n search: string\n loading: boolean\n sending: boolean\n\n /** `autoSelect: false` lists without opening (and marking read) the first\n * conversation — the compact floating inbox starts on the list. */\n load(opts?: { autoSelect?: boolean }): Promise<void>\n select(id: string): Promise<void>\n /** Dar por vista SEM abrir — o \"ok, obrigado\" que não pede resposta. */\n markRead(id: string): Promise<void>\n deselect(): void\n setChannelFilter(channel: Channel | 'all'): Promise<void>\n setLeadOwnerFilter(ownerId?: string | 'none'): Promise<void>\n setSearch(search: string): Promise<void>\n create(input: CreateConversationInput): Promise<Conversation>\n /** Abrir a conversa DESTA pessoa neste canal, criando-a se ainda não houver. */\n openForPerson(input: OpenForPersonInput): Promise<Conversation>\n send(body: string): Promise<void>\n setStatus(status: ConversationStatus): Promise<void>\n}\n\nexport function createConversationsStore(\n provider: ConversationsProvider,\n): StoreApi<ConversationsUIState> {\n return createStore<ConversationsUIState>((set, get) => ({\n conversations: [],\n messages: [],\n selectedId: null,\n channelFilter: 'all',\n leadOwnerFilter: undefined,\n search: '',\n loading: false,\n sending: false,\n\n async load(opts) {\n set({ loading: true })\n const conversations = await provider.listConversations({\n channel: get().channelFilter,\n leadOwnerId: get().leadOwnerFilter,\n search: get().search || undefined,\n })\n const selectedId = get().selectedId ?? (opts?.autoSelect === false ? null : conversations[0]?.id ?? null)\n set({ conversations, loading: false, selectedId })\n if (selectedId) await get().select(selectedId)\n },\n\n /** Dar por vista sem abrir — o caso do \"ok, obrigado\" que não pede resposta. */\n async markRead(id: string) {\n await provider.markRead(id)\n const agora = new Date().toISOString()\n set((s) => ({\n conversations: s.conversations.map((c) => (\n c.id === id ? { ...c, unreadCount: 0, acknowledgedAt: agora } : c\n )),\n }))\n },\n\n async select(id: string) {\n set({ selectedId: id })\n const messages = await provider.getMessages(id)\n set({ messages })\n await provider.markRead(id)\n // `acknowledgedAt` junto, e não só o contador: é ele que tira a conversa\n // da fila. Sem isto a bolinha continuava acesa depois de abrir e ler.\n const agora = new Date().toISOString()\n set((s) => ({\n conversations: s.conversations.map((c) => (\n c.id === id ? { ...c, unreadCount: 0, acknowledgedAt: agora } : c\n )),\n }))\n },\n\n /** Relê as mensagens da conversa aberta, sem tocar em mais nada.\n *\n * O status de uma mensagem de WhatsApp muda DEPOIS do envio — entregue,\n * lida, às vezes minutos depois — e quem avisa é o webhook, que escreve no\n * banco sem a tela saber. Sem isto a caixa mostra para sempre o status do\n * instante do envio: um tique só, numa mensagem que já foi lida.\n *\n * Não usa `select()` de propósito: aquele marca a conversa como lida e\n * zera o contador, e uma releitura de fundo não é um gesto de ninguém. */\n async refreshMessages() {\n const id = get().selectedId\n if (!id) return\n try {\n const messages = await provider.getMessages(id)\n // Só escreve se mudou algo. `set` a cada dez segundos redesenharia a\n // thread inteira e roubaria a seleção de texto de quem está lendo.\n const before = get().messages\n const same = before.length === messages.length &&\n before.every((m, i) => m.id === messages[i].id && m.deliveryStatus === messages[i].deliveryStatus)\n if (!same) set({ messages })\n } catch { /* a caixa continua com o que tem; a próxima volta tenta de novo */ }\n },\n\n deselect() {\n set({ selectedId: null, messages: [] })\n },\n\n async setLeadOwnerFilter(ownerId) {\n set({ leadOwnerFilter: ownerId })\n await get().load()\n },\n\n async setChannelFilter(channel) {\n set({ channelFilter: channel })\n await get().load()\n },\n\n async setSearch(search) {\n set({ search })\n await get().load()\n },\n\n async create(input) {\n const created = await provider.createConversation(input)\n // The thread EXISTS the moment the insert returns, so resolve on that and\n // show it optimistically. Clear filters that would hide it, prepend it,\n // select it — all local.\n set((s) => ({\n channelFilter: 'all',\n search: '',\n conversations: [created, ...s.conversations.filter((c) => c.id !== created.id)],\n selectedId: created.id,\n }))\n\n // Reconciliation (authoritative list + the thread's messages) runs in the\n // BACKGROUND. It used to be awaited here, which made the caller — the\n // compose modal — hostage to two extra round-trips: on a slow pool the\n // conversation was already in the database while the modal sat open\n // looking broken, inviting a second click and a duplicate thread.\n // Failures are non-fatal: the optimistic row above already renders.\n void (async () => {\n try {\n const conversations = await provider.listConversations({})\n // Read-after-write guard: a refetch that races the insert may not\n // return the new row yet — keep the local one rather than dropping it.\n const merged = conversations.some((c) => c.id === created.id)\n ? conversations\n : [created, ...conversations]\n set({ conversations: merged })\n await get().select(created.id)\n } catch {\n /* optimistic state stands; the next load() reconciles */\n }\n })()\n\n return created\n },\n\n // Chegar aqui vindo de fora — da ficha de um lead, por exemplo — não pode\n // criar uma segunda thread com alguém com quem a casa já conversa. Procura\n // primeiro pela PESSOA, e só então pelo telefone: o vínculo é a verdade, e\n // o handle é o que resgata threads criadas antes de o vínculo existir.\n async openForPerson({ personId, name, handle, channel }) {\n // Uma caixa ainda não carregada não tem como saber que a thread existe.\n if (get().conversations.length === 0 && !get().loading) {\n try { await get().load() } catch { /* segue para a criação */ }\n }\n const key = handleKey(handle)\n const existing = get().conversations.find((c) =>\n c.channel === channel &&\n ((personId && c.contactPersonId === personId) ||\n (key !== '' && handleKey(c.contactHandle) === key)))\n\n if (existing) {\n // Limpa o que esconderia a thread: chegar por link e cair numa lista\n // filtrada é indistinguível de a conversa não existir.\n set({ channelFilter: 'all', search: '' })\n await get().select(existing.id)\n return existing\n }\n\n return get().create({\n contactName: name,\n contactPersonId: personId,\n contactHandle: handle,\n channel,\n })\n },\n\n async send(body: string) {\n const id = get().selectedId\n if (!id || !body.trim()) return\n set({ sending: true })\n const created = await provider.sendMessage({ conversationId: id, body: body.trim() })\n set((s) => ({\n sending: false,\n messages: [...s.messages, created],\n conversations: s.conversations.map((c) =>\n // `lastMessageDirection` acompanha a prévia, senão a fila mente. O\n // gatilho da migration 001 carimba a coluna no banco, mas a lista só\n // volta a ler no próximo `load()` — e até lá a thread que ACABOU de\n // ser respondida continua em \"esperando nós\", que é exatamente a\n // pergunta que essa coluna existe para responder.\n //\n // Antes da 001 isto não aparecia: a coluna vinha sempre indefinida e\n // `isWaitingOnUs` caía no `unreadCount`. A migration não criou o\n // defeito, tornou-o visível.\n c.id === id\n ? { ...c, lastMessagePreview: created.body, lastMessageAt: created.at, lastMessageDirection: 'outbound' as const }\n : c,\n ),\n }))\n },\n\n async setStatus(status) {\n const id = get().selectedId\n if (!id) return\n const updated = await provider.setStatus(id, status)\n set((s) => ({\n conversations: s.conversations.map((c) => (c.id === id ? updated : c)),\n }))\n },\n }))\n}\n","export const en: Record<string, string> = {\n \"conversations.markRead\": \"Mark as read\",\n 'conversations.title': 'Conversations',\n 'conversations.subtitle': 'Unified inbox across every channel',\n\n // Conversation list\n 'conversations.list.search': 'Search conversations',\n 'conversations.list.loading': 'Loading…',\n 'conversations.list.empty': 'No conversations',\n 'conversations.filter.notConnected': 'Account not connected yet',\n 'conversations.list.new': 'New conversation',\n\n // Channel filters\n 'conversations.filter.all': 'All',\n 'conversations.filter.whatsapp': 'WhatsApp',\n 'conversations.filter.sms': 'SMS',\n 'conversations.filter.instagram': 'Instagram',\n 'conversations.filter.email': 'Email',\n 'conversations.filter.webchat': 'Web',\n\n // Status labels\n 'conversations.status.open': 'Open',\n 'conversations.status.snoozed': 'Snoozed',\n 'conversations.status.closed': 'Closed',\n\n // Empty state\n 'conversations.empty.select': 'Select a conversation to start chatting',\n\n // Thread\n 'conversations.thread.back': 'Back to conversations',\n 'conversations.thread.snooze': 'Snooze',\n 'conversations.thread.close': 'Close',\n 'conversations.thread.details': 'Toggle contact details',\n 'conversations.thread.empty': 'No messages yet',\n 'conversations.thread.reply': 'Reply via {{channel}}…',\n 'conversations.thread.send': 'Send',\n\n // Contact panel\n 'conversations.contact.details': 'Details',\n 'conversations.contact.closeDetails': 'Close details',\n 'conversations.contact.channel': 'Channel',\n 'conversations.contact.status': 'Status',\n 'conversations.filter.anyOwner': 'Any owner',\n 'conversations.filter.noOwner': 'No owner',\n 'conversations.contact.leadOwner': 'Lead owner',\n 'conversations.contact.assignedTo': 'Assigned to',\n 'conversations.contact.location': 'Location',\n 'conversations.contact.tags': 'Tags',\n 'conversations.contact.note': 'Note',\n 'conversations.contact.linkedRecords': 'Linked records',\n 'conversations.contact.noLinkedRecords': 'No linked records yet.',\n\n // New-conversation modal\n 'conversations.new.title': 'New conversation',\n 'conversations.new.channel': 'Channel',\n 'conversations.new.contactName': 'Contact name',\n 'conversations.new.contactNamePlaceholder': 'e.g. Jane Doe',\n 'conversations.new.handle': 'Phone / handle / email',\n 'conversations.new.handlePlaceholder': '+1 555 000 0000',\n // The handle field only surfaces when the picked contact has nothing usable\n // for the active channel — otherwise it is derived and shown on the chip.\n 'conversations.new.addHandle': 'Add {label}',\n 'conversations.new.handleLabel.phone': 'phone',\n 'conversations.new.handleLabel.email': 'email',\n 'conversations.new.handleLabel.instagram': 'Instagram handle',\n 'conversations.new.handleLabel.webchat': 'web chat id',\n 'conversations.new.firstMessage': 'First message',\n 'conversations.new.firstMessagePlaceholder': 'Write the first message (optional)…',\n 'conversations.new.cancel': 'Cancel',\n 'conversations.new.create': 'Start conversation',\n 'conversations.new.creating': 'Starting…',\n 'conversations.new.createFailed': 'Could not create the conversation',\n\n // Dashboard — the queue of people waiting on a reply\n 'conversations.dashboard.waiting': 'Waiting on you',\n 'conversations.dashboard.waitingOldest': 'Oldest waiting {{time}}',\n 'conversations.dashboard.waitingNone': 'Nobody waiting',\n 'conversations.dashboard.openThreads': 'Open conversations',\n 'conversations.dashboard.openThreadsSub': '{{count}} waiting on a reply',\n 'conversations.dashboard.needsYou': 'Needs you',\n 'conversations.dashboard.needsYouEmpty': 'Nobody waiting. Inbox is clear.',\n 'conversations.dashboard.who': 'Who',\n 'conversations.dashboard.waited': 'Waiting',\n 'conversations.waited.minutes': '{{count}} min',\n 'conversations.waited.hours': '{{count}} h',\n 'conversations.waited.days': '{{count}} d',\n\n // Inbox settings\n 'conversations.settings.title': 'Conversations',\n 'conversations.settings.channels': 'Your numbers',\n 'conversations.settings.channelsHelp': 'Where messages come in and go out. Connect and manage channels in the Integrations tab.',\n 'conversations.settings.channelsEmpty': 'No channel connected yet — until then the inbox stays empty. Connect WhatsApp in the Integrations tab.',\n 'conversations.settings.channelsUnavailable': 'Could not load your channels right now.',\n 'conversations.settings.channelDedicated': 'Your own number',\n 'conversations.settings.channelShared': 'Platform number',\n 'conversations.settings.status.active': 'Active',\n 'conversations.settings.status.requested': 'Requested',\n 'conversations.settings.status.provisioning': 'Provisioning',\n 'conversations.settings.status.provisioned': 'Provisioned',\n 'conversations.settings.status.verifying': 'Verifying',\n 'conversations.settings.status.failed': 'Failed',\n 'conversations.settings.status.released': 'Released',\n 'conversations.settings.status.disconnected': 'Disconnected',\n}\n","export const ptBR: Record<string, string> = {\n \"conversations.markRead\": \"Marcar como lida\",\n 'conversations.title': 'Conversas',\n 'conversations.subtitle': 'Caixa de entrada unificada de todos os canais',\n\n // Lista de conversas\n 'conversations.list.search': 'Buscar conversas',\n 'conversations.list.loading': 'Carregando…',\n 'conversations.list.empty': 'Nenhuma conversa',\n 'conversations.filter.notConnected': 'Conta ainda não conectada',\n 'conversations.list.new': 'Nova conversa',\n\n // Filtros de canal\n 'conversations.filter.all': 'Todas',\n 'conversations.filter.whatsapp': 'WhatsApp',\n 'conversations.filter.sms': 'SMS',\n 'conversations.filter.instagram': 'Instagram',\n 'conversations.filter.email': 'E-mail',\n 'conversations.filter.webchat': 'Web',\n\n // Rótulos de status\n 'conversations.status.open': 'Aberta',\n 'conversations.status.snoozed': 'Adiada',\n 'conversations.status.closed': 'Encerrada',\n\n // Estado vazio\n 'conversations.empty.select': 'Selecione uma conversa para começar a conversar',\n\n // Thread\n 'conversations.thread.back': 'Voltar às conversas',\n 'conversations.thread.snooze': 'Adiar',\n 'conversations.thread.close': 'Encerrar',\n 'conversations.thread.details': 'Alternar detalhes do contato',\n 'conversations.thread.empty': 'Nenhuma mensagem ainda',\n 'conversations.thread.reply': 'Responder via {{channel}}…',\n 'conversations.thread.send': 'Enviar',\n\n // Painel do contato\n 'conversations.contact.details': 'Detalhes',\n 'conversations.contact.closeDetails': 'Fechar detalhes',\n 'conversations.contact.channel': 'Canal',\n 'conversations.contact.status': 'Status',\n 'conversations.filter.anyOwner': 'Qualquer dono',\n 'conversations.filter.noOwner': 'Sem dono',\n 'conversations.contact.leadOwner': 'Dono do lead',\n 'conversations.contact.assignedTo': 'Responsável',\n 'conversations.contact.location': 'Localização',\n 'conversations.contact.tags': 'Etiquetas',\n 'conversations.contact.note': 'Nota',\n 'conversations.contact.linkedRecords': 'Registros vinculados',\n 'conversations.contact.noLinkedRecords': 'Nenhum registro vinculado ainda.',\n\n // Modal de nova conversa\n 'conversations.new.title': 'Nova conversa',\n 'conversations.new.channel': 'Canal',\n 'conversations.new.contactName': 'Nome do contato',\n 'conversations.new.contactNamePlaceholder': 'ex.: Maria Silva',\n 'conversations.new.handle': 'Telefone / usuário / e-mail',\n 'conversations.new.handlePlaceholder': '+55 11 99999-0000',\n // O campo de handle só aparece quando o contato escolhido não tem o dado do\n // canal ativo — caso contrário ele é derivado e mostrado no chip.\n 'conversations.new.addHandle': 'Adicionar {label}',\n 'conversations.new.handleLabel.phone': 'telefone',\n 'conversations.new.handleLabel.email': 'e-mail',\n 'conversations.new.handleLabel.instagram': '@ do Instagram',\n 'conversations.new.handleLabel.webchat': 'id do chat',\n 'conversations.new.firstMessage': 'Primeira mensagem',\n 'conversations.new.firstMessagePlaceholder': 'Escreva a primeira mensagem (opcional)…',\n 'conversations.new.cancel': 'Cancelar',\n 'conversations.new.create': 'Iniciar conversa',\n 'conversations.new.creating': 'Iniciando…',\n 'conversations.new.createFailed': 'Não foi possível criar a conversa',\n\n // Painel — a fila de quem está esperando resposta\n 'conversations.dashboard.waiting': 'Esperando resposta',\n 'conversations.dashboard.waitingOldest': 'A mais antiga há {{time}}',\n 'conversations.dashboard.waitingNone': 'Ninguém na fila',\n 'conversations.dashboard.openThreads': 'Conversas abertas',\n 'conversations.dashboard.openThreadsSub': '{{count}} esperando resposta',\n 'conversations.dashboard.needsYou': 'Precisa de você',\n 'conversations.dashboard.needsYouEmpty': 'Ninguém esperando. Caixa de entrada em dia.',\n 'conversations.dashboard.who': 'Quem',\n 'conversations.dashboard.waited': 'Esperando há',\n 'conversations.waited.minutes': '{{count}} min',\n 'conversations.waited.hours': '{{count}} h',\n 'conversations.waited.days': '{{count}} d',\n\n // Configurações da caixa de entrada\n 'conversations.settings.title': 'Conversas',\n 'conversations.settings.channels': 'Seus números',\n 'conversations.settings.channelsHelp': 'Por onde a mensagem entra e sai. Ligue e gerencie os canais na aba Integrações.',\n 'conversations.settings.channelsEmpty': 'Nenhum canal ligado ainda — enquanto isso, a caixa de entrada fica vazia. Ligue o WhatsApp na aba Integrações.',\n 'conversations.settings.channelsUnavailable': 'Não foi possível consultar seus canais agora.',\n 'conversations.settings.channelDedicated': 'Número só seu',\n 'conversations.settings.channelShared': 'Número da plataforma',\n 'conversations.settings.status.active': 'Ativo',\n 'conversations.settings.status.requested': 'Solicitado',\n 'conversations.settings.status.provisioning': 'Provisionando',\n 'conversations.settings.status.provisioned': 'Provisionado',\n 'conversations.settings.status.verifying': 'Verificando',\n 'conversations.settings.status.failed': 'Falhou',\n 'conversations.settings.status.released': 'Devolvido',\n 'conversations.settings.status.disconnected': 'Desconectado',\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const conversationsLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","import React, { useEffect, useMemo } from 'react'\nimport type { StoreApi } from 'zustand'\nimport type { DashboardWidgetDef } from '@fayz-ai/core'\nimport { useTranslation, navigateApp } from '@fayz-ai/core'\nimport {\n KpiCard, TableWidget, defineKpiWidget, defineTableWidget,\n type TableWidgetProps,\n} from '@fayz-ai/ui'\nimport {\n ConversationsContextProvider,\n useConversationsStore,\n type ResolvedConversationsConfig,\n} from '../context'\nimport type { ConversationsUIState } from '../store'\nimport { isWaitingOnUs, type Conversation } from '../types'\n\n// ---------------------------------------------------------------------------\n// Inbox widgets for the dashboard registry.\n//\n// This plugin registered nothing here until now, which meant the one number a\n// front desk actually opens the day for — \"who is waiting on me\" — existed on\n// no surface but the inbox itself. A dashboard that shows revenue and pipeline\n// while somebody has been waiting since Tuesday is reporting on the past.\n//\n// ── What \"waiting\" means ──────────────────────────────────────────────────\n//\n// `isWaitingOnUs` (see ../types), and not a rule spelled out again here: the\n// KPI, the table and anything that later filters the inbox have to agree, and a\n// dashboard that says three while the list shows one is worse than neither.\n//\n// It reads `lastMessageDirection`, which migration 001 added and a trigger\n// keeps current. The first pass of this file used `unreadCount > 0` because the\n// column did not exist — an approximation that missed the case that hurts\n// most: a thread somebody opened, read, meant to answer later and forgot. Zero\n// unread, customer still waiting. The fallback is still there for threads that\n// genuinely do not know their direction.\n// ---------------------------------------------------------------------------\n\n/** The store dedups the fetch, so every widget may ensure its own data. */\nfunction useEnsureConversations() {\n const load = useConversationsStore((s) => s.load)\n const loaded = useConversationsStore((s) => s.conversations.length > 0)\n useEffect(() => { if (!loaded) void load() }, [])\n}\n\nfunction useWaiting(): { waiting: Conversation[]; open: number; loading: boolean } {\n useEnsureConversations()\n const conversations = useConversationsStore((s) => s.conversations)\n const loading = useConversationsStore((s) => s.loading)\n return useMemo(() => {\n const open = conversations.filter((c) => c.status === 'open')\n const waiting = open\n .filter(isWaitingOnUs)\n // Oldest first: the list is a queue, and a queue that puts the newest\n // arrival on top is the reason somebody waits three days.\n .sort((a, b) => Date.parse(a.lastMessageAt) - Date.parse(b.lastMessageAt))\n return { waiting, open: open.length, loading }\n }, [conversations, loading])\n}\n\n/**\n * How long they have been waiting, in the coarsest unit that is still true.\n *\n * Minutes for the first hour, then hours, then days — an exact \"2h 14min\" reads\n * as precision about something nobody measures that finely, and it is one more\n * number to parse in a cell that exists to be scanned.\n */\nfunction waitedFor(iso: string, t: (key: string, vars?: Record<string, string>) => string): string {\n const ms = Date.now() - Date.parse(iso)\n if (!Number.isFinite(ms) || ms < 0) return '—'\n const minutes = Math.floor(ms / 60000)\n if (minutes < 60) return t('conversations.waited.minutes', { count: String(Math.max(minutes, 1)) })\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return t('conversations.waited.hours', { count: String(hours) })\n return t('conversations.waited.days', { count: String(Math.floor(hours / 24)) })\n}\n\n// ---------------------------------------------------------------------------\n// KPIs\n// ---------------------------------------------------------------------------\n\nfunction WaitingKpi() {\n const t = useTranslation()\n const { waiting, loading } = useWaiting()\n const oldest = waiting[0]\n return (\n <KpiCard\n label={t('conversations.dashboard.waiting')}\n icon=\"MessageCircleWarning\"\n loading={loading && waiting.length === 0}\n value={String(waiting.length)}\n // The count alone does not say whether this is a busy morning or a\n // failure: three people waiting ten minutes is a queue, one person\n // waiting two days is an apology.\n sub={\n oldest\n ? t('conversations.dashboard.waitingOldest', { time: waitedFor(oldest.lastMessageAt, t) })\n : t('conversations.dashboard.waitingNone')\n }\n // More is worse here, so the arrow has to be read the other way round.\n invertTrend\n />\n )\n}\n\nfunction OpenThreadsKpi() {\n const t = useTranslation()\n const { open, waiting, loading } = useWaiting()\n return (\n <KpiCard\n label={t('conversations.dashboard.openThreads')}\n icon=\"MessagesSquare\"\n loading={loading && open === 0}\n value={String(open)}\n sub={t('conversations.dashboard.openThreadsSub', { count: String(waiting.length) })}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// The queue itself\n// ---------------------------------------------------------------------------\n\nfunction WaitingTable() {\n const t = useTranslation()\n const { waiting, loading } = useWaiting()\n\n // Column type borrowed from the widget that consumes it rather than from\n // @tanstack/react-table directly: this plugin has no table dependency of its\n // own, and adding one to name a type would put a second copy of the table\n // library in the tree of every app that installs the inbox.\n const columns = useMemo<TableWidgetProps<Conversation>['columns']>(() => [\n {\n accessorKey: 'contactName',\n header: t('conversations.dashboard.who'),\n cell: ({ row }) => (\n <span className=\"font-medium\">{row.original.contactName}</span>\n ),\n },\n {\n id: 'preview',\n header: '',\n // The message, not just the name: half of triage is deciding which of\n // five waiting people is the one worth answering first, and that is\n // decided by what they said.\n cell: ({ row }) => (\n <span className=\"line-clamp-1 text-xs text-muted-foreground\">{row.original.lastMessagePreview}</span>\n ),\n },\n {\n id: 'channel',\n header: t('conversations.contact.channel'),\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {t(`conversations.filter.${row.original.channel}`)}\n </span>\n ),\n },\n {\n id: 'waited',\n header: t('conversations.dashboard.waited'),\n cell: ({ row }) => (\n <span className=\"whitespace-nowrap text-xs font-medium tabular-nums\">\n {waitedFor(row.original.lastMessageAt, t)}\n </span>\n ),\n },\n ], [t])\n\n return (\n <TableWidget\n title={t('conversations.dashboard.needsYou')}\n icon=\"MessageCircleWarning\"\n columns={columns}\n data={waiting}\n loading={loading && waiting.length === 0}\n emptyMessage={t('conversations.dashboard.needsYouEmpty')}\n // Straight into the thread. A widget that names a person waiting and then\n // makes you go find them in a list is a notification, not a queue.\n onRowClick={(row) => { navigateApp(`/conversations?thread=${row.id}`) }}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// Registry builder — each widget carries its own provider, so it renders on the\n// app home with no inbox page around it.\n// ---------------------------------------------------------------------------\n\nexport function createConversationsDashboardWidgets(ctx: {\n store: StoreApi<ConversationsUIState>\n config: ResolvedConversationsConfig\n}): DashboardWidgetDef[] {\n const withCtx = (Inner: React.ComponentType): React.ComponentType<unknown> => {\n const Wrapped = () => (\n <ConversationsContextProvider store={ctx.store} config={ctx.config}>\n <Inner />\n </ConversationsContextProvider>\n )\n Wrapped.displayName = `ConversationsWidget(${Inner.displayName ?? Inner.name})`\n return Wrapped\n }\n\n return [\n // Visible on the home by DEFAULT, unlike most plugin widgets. The rest of\n // the registry is opt-in because a dashboard of everything is a dashboard\n // of nothing — but an unanswered customer is the one item on any home\n // screen that is time-critical, and hiding it behind Customize means it\n // only reaches the people who already knew to look.\n defineKpiWidget({\n id: 'conversations.kpi.waiting',\n title: 'conversations.dashboard.waiting',\n domain: 'conversations',\n defaultOrder: -1,\n component: withCtx(WaitingKpi),\n }),\n defineKpiWidget({\n id: 'conversations.kpi.open',\n title: 'conversations.dashboard.openThreads',\n domain: 'conversations',\n defaultOrder: 4,\n defaultVisible: false,\n component: withCtx(OpenThreadsKpi),\n }),\n defineTableWidget({\n id: 'conversations.table.waiting',\n title: 'conversations.dashboard.needsYou',\n domain: 'conversations',\n span: 2,\n defaultOrder: 10,\n component: withCtx(WaitingTable),\n }),\n ]\n}\n","import { countByTenant, type OnboardingProgramDef } from '@fayz-ai/core'\nimport { T } from '../data/tables'\n\n/**\n * Implantação da caixa de entrada — um canal e um hábito.\n *\n * Ordem 30, à frente da base do workspace (50) e do CRM (80), e isso é uma\n * opinião: numa operação que atende, o cliente escreve antes de qualquer outra\n * coisa acontecer. Convidar a equipe e desenhar o funil são trabalho de quem já\n * tem alguém escrevendo; ligar o canal é o que faz aparecer o primeiro.\n *\n * Dois passos, e o segundo não é uma tela. A caixa de entrada é o módulo que\n * mais parece pronto vazio: ela abre, tem filtro por canal, tem busca — e não\n * chega mensagem nenhuma porque ninguém ligou o número. O passo que fecha é o\n * único que prova que o caminho inteiro existe: uma mensagem que entrou e foi\n * respondida daqui.\n */\nexport function buildConversationsOnboarding(): OnboardingProgramDef {\n return {\n id: 'conversations',\n title: 'Quem fala com você',\n order: 30,\n role: 'frontdesk',\n instructions: `Você está ligando a caixa de entrada. O risco aqui não é a pessoa não achar a tela — é ela achar a tela, ver que está vazia e concluir que o produto não funciona.\n\n- Comece pelo CANAL. Sem número ligado não entra mensagem nenhuma, e todo o resto do módulo é decoração. O caminho é Configurações › Conversas › Integrações.\n- Explique a diferença entre o número da plataforma e um número dedicado ANTES de ela escolher: no compartilhado ela já começa a receber hoje; no dedicado sai o nome dela, mas ainda passa por um cadastro na Meta.\n- O segundo passo é a prova: peça para ela mandar uma mensagem do próprio celular para o número e responder daqui. É o que mostra que ida e volta funcionam.\n- Se ela já tem WhatsApp Business no celular, diga com todas as letras o que muda: as conversas passam a ficar aqui, onde a equipe inteira vê, em vez de num aparelho só.`,\n steps: [\n {\n key: 'channel',\n title: 'Ligue o canal onde seu cliente já fala',\n description: 'Sem número conectado, a caixa de entrada abre vazia para sempre.',\n icon: 'MessageCircle',\n route: '/settings/conversations/_integrations',\n priority: 'urgent',\n // O passo É a tela: um app que monte o inbox sem a rota de configurações\n // não tem onde ligar canal nenhum, e a linha ficaria aberta para sempre.\n requiresRoute: true,\n agentHint:\n 'Abra Integrações e apresente as duas opções pelo que elas custam à pessoa HOJE: o número da plataforma começa a receber agora, o dedicado sai com o nome dela mas espera o cadastro na Meta.',\n howTo:\n 'Configurações › Conversas › Integrações › Tyxter. O número da plataforma já está ligado e é compartilhado com outros negócios — dá para começar a receber por ele hoje. Um número dedicado sai só com o seu nome, libera os seus próprios modelos de mensagem e tem limite de envio próprio; ele é alugado no mês e ainda passa por um cadastro rápido na Meta antes do primeiro envio.',\n celebrate: 'Canal ligado — agora dá para te acharem 📲',\n script: [\n { kind: 'goto', route: '/settings/conversations/_integrations' },\n {\n kind: 'ask',\n text: 'Estamos nas Integrações da caixa de entrada. Mostre o número da plataforma e o dedicado, explique o que muda em cada um e ajude a pessoa a escolher.',\n },\n ],\n check: async () => (await countByTenant(T.channels)) > 0,\n },\n {\n key: 'first-reply',\n title: 'Receba e responda a primeira mensagem',\n description: 'A prova de que a ida e a volta funcionam.',\n icon: 'Send',\n route: '/conversations',\n priority: 'high',\n agentHint:\n 'Não é passo de cadastro. Peça para a pessoa mandar uma mensagem do próprio celular para o número ligado e responder aqui de dentro — e fique com ela até a resposta chegar do outro lado.',\n howTo:\n 'Pegue o seu celular, mande uma mensagem qualquer para o número que você acabou de ligar e volte aqui: a conversa aparece em Conversas. Responda por aqui e confira que chegou no celular. É o teste que prova que a caixa de entrada está no ar — e é também como a equipe vai trabalhar todo dia, com a conversa num lugar que todo mundo vê em vez de num aparelho só.',\n celebrate: 'Ida e volta funcionando 💬',\n // A conversa existe assim que a primeira mensagem entra, então a\n // contagem de threads é a checagem — e não a de mensagens, que seria\n // fechada por um envio que ninguém respondeu.\n check: async () => (await countByTenant(T.conversations)) > 0,\n },\n ],\n }\n}\n","// The one place that names the Tyxter number-claim data plane.\n//\n// Kept apart from connectorDef.tsx for the reason data.ts exists on the Kiwify\n// and Stripe connectors: the credential path is the half that moves when the\n// platform broker lands, and when it does only this file should change.\nimport {\n CONNECTOR_RUNTIME_TOKEN_HEADER,\n connectorRuntimeToken,\n getSupabaseClientOptional,\n} from '@fayz-ai/core'\n\n/** The edge function that holds every phone-number call this connector makes. */\nexport const TYXTER_NUMBER_CLAIM_FUNCTION = 'tyxter-number-claim'\n\n/** The channel row, as the function hands it back. A subset of the table on purpose. */\nexport interface ClaimedChannel {\n id: string\n channel: string\n provider: string\n /** Null while the row is still a reservation with no number behind it. */\n providerNumberId: string | null\n phoneE164: string | null\n kind: string\n status: string\n displayName: string | null\n}\n\n/**\n * Where to send the human to finish the Meta registration, and how good the\n * link is.\n *\n * `source` is surfaced rather than hidden because the three are not equivalent:\n * 'session' returns the person to this very panel and names the tenant to Meta;\n * 'error_link' is the provider's own pre-targeted page; 'default' is the generic\n * dashboard, which works but assumes the browser is signed into the right\n * organization. The panel says less when the source is worse.\n */\nexport interface MetaRegistrationHandoff {\n source: 'session' | 'error_link' | 'default'\n url: string\n note: string | null\n sessionId?: string\n expiresAt?: string | null\n}\n\nexport interface ClaimResult {\n channel: ClaimedChannel\n metaRegistration: MetaRegistrationHandoff | null\n}\n\ninterface MinimalClient {\n functions: {\n invoke: (\n name: string,\n options: { body: unknown; headers?: Record<string, string> },\n ) => Promise<{ data: unknown; error: { message: string } | null }>\n }\n}\n\nfunction client(): MinimalClient {\n const supabase = getSupabaseClientOptional() as MinimalClient | null\n if (!supabase) throw new Error('Sem conexão com o banco para falar com a Tyxter.')\n return supabase\n}\n\n/**\n * One call to the data plane.\n *\n * The Supabase session rides in `Authorization` — the gateway checks it, and the\n * function re-checks membership in the tenant against it, because renting a\n * number costs money every month.\n *\n * The runtime token is BEST-EFFORT here, unlike on Kiwify. There it identifies\n * whose credential to redeem and a call without it is unanswerable; here the\n * credential is the platform's own, held once for the whole product, and the\n * function falls back to machine redemption keyed by the tenant. An app that\n * installed no token source can still claim a number, which is the right\n * outcome — refusing would be enforcing a requirement that does not exist.\n */\nasync function invoke<T>(body: Record<string, unknown>): Promise<T> {\n let headers: Record<string, string> | undefined\n try {\n headers = { [CONNECTOR_RUNTIME_TOKEN_HEADER]: await connectorRuntimeToken({ tenantId: String(body.tenantId ?? '') }) }\n } catch {\n headers = undefined\n }\n\n const { data, error } = await client().functions.invoke(TYXTER_NUMBER_CLAIM_FUNCTION, {\n body,\n ...(headers ? { headers } : {}),\n })\n if (error) throw new Error(error.message)\n return data as T\n}\n\n/**\n * A page address, cleaned up for `return_url`.\n *\n * The provider's allowlist refuses a URL carrying a fragment, credentials or a\n * non-https scheme, so the fragment goes — and this app is a hash router, which\n * means the fragment is the WHOLE route. Losing it returns the human to the\n * app's front door rather than to this panel, which is a smaller failure than a\n * session the provider refuses to create at all.\n */\nexport function returnUrlFrom(href: string | null | undefined): string | null {\n if (!href) return null\n try {\n const url = new URL(href)\n url.hash = ''\n url.username = ''\n url.password = ''\n return url.toString()\n } catch {\n return null\n }\n}\n\n/** The page the human is standing on, as a `return_url` the provider will accept. */\nexport function currentReturnUrl(): string | null {\n return typeof window === 'undefined' ? null : returnUrlFrom(window.location.href)\n}\n\n/** Rent a dedicated number for this tenant, in the given area code. */\nexport function claimDedicatedNumber(input: { tenantId: string; ddd: string }): Promise<ClaimResult> {\n return invoke<ClaimResult>({\n action: 'claim',\n tenantId: input.tenantId,\n ddd: input.ddd,\n returnUrl: currentReturnUrl(),\n })\n}\n\n/**\n * Re-read the tenant's numbers at the provider and sync the rows.\n *\n * The poll the panel runs while a claim is pending. It is not redundant with the\n * webhook: four of the five lifecycle steps emit no event at all (verified\n * live — a full provision to `active` produced zero `phone_number.*` events), so\n * without this the row would sit on \"Solicitado\" until the day the number is\n * disconnected.\n */\nexport function refreshDedicatedNumbers(tenantId: string): Promise<{ channels: ClaimedChannel[] }> {\n return invoke<{ channels: ClaimedChannel[] }>({ action: 'status', tenantId })\n}\n\n/** The link that hands the human to Meta's Embedded Signup, which no key can do headlessly. */\nexport function metaRegistrationHandoff(tenantId: string): Promise<{\n metaRegistration: MetaRegistrationHandoff | null\n channel: ClaimedChannel\n}> {\n return invoke({ action: 'handoff', tenantId, returnUrl: currentReturnUrl() })\n}\n","// \"Can this app take a Pix inside a conversation?\" — asked from the browser,\n// answered by the provider.\n//\n// It is a function call and not a table read because the answer does not live in\n// this pool. It lives at the provider, behind the PLATFORM's key, which a\n// browser must never hold — so `tyxter-payment-preflight` asks on the panel's\n// behalf and hands back only the verdict. There is nothing to cache here: a\n// merchant who has just finished the credential handoff is exactly the person\n// pressing the button again.\nimport { getActiveTenantId, getSupabaseClientOptional } from '@fayz-ai/core'\n\n/** The edge function that holds both questions. */\nexport const PAYMENT_PREFLIGHT_FUNCTION = 'tyxter-payment-preflight'\n\n/**\n * Which rail is actually behind the payments channel.\n *\n * The distinction that matters and is easy to collapse: `sandbox_default` is\n * READY — charges open, settle and fire webhooks — but the money is not real,\n * and the transparent-Pix provider options are refused. A green badge over it\n * is how a salon finds out on the day of its first real charge, so the panel\n * says \"sandbox\" beside the tick instead.\n */\nexport type PaymentActiveMode = 'sandbox_default' | 'iniciador' | 'abacate_pay'\n\nexport interface PaymentReadiness {\n /** The provider's own verdict. True for the sandbox fixture too — see `sandbox`. */\n ready: boolean\n status: string\n mode: PaymentActiveMode | null\n /** `mode === 'sandbox_default'`: ready, but not with real money. */\n sandbox: boolean\n environment: string | null\n /** Why not, when the provider says why. */\n reason: string | null\n}\n\n/** The browser handoff where the merchant enters credentials this app never sees. */\nexport interface PaymentSetupSession {\n setupUrl: string | null\n requestId: string | null\n expiresAt: string | null\n environment: string | null\n}\n\ninterface MinimalClient {\n functions: {\n invoke: (\n name: string,\n options: { body: unknown },\n ) => Promise<{ data: unknown; error: { message: string } | null }>\n }\n}\n\nasync function invoke<T>(body: Record<string, unknown>, tenantId?: string): Promise<T> {\n const supabase = getSupabaseClientOptional() as MinimalClient | null\n if (!supabase) throw new Error('Sem conexão com o banco para verificar os pagamentos.')\n const tenant = tenantId ?? getActiveTenantId()\n if (!tenant) throw new Error('Sem negócio selecionado.')\n\n const { data, error } = await supabase.functions.invoke(PAYMENT_PREFLIGHT_FUNCTION, {\n body: { ...body, tenantId: tenant },\n })\n if (!error) return data as T\n\n // supabase-js buries the function's own body in the error context. Without\n // digging it out every refusal reads as \"Edge Function returned a non-2xx\n // status code\", which is what \"not connected\", \"no key\" and a CORS preflight\n // all look like — while the function answered each with a sentence.\n let message = ''\n try {\n const payload = (await (error as { context?: { json?: () => Promise<unknown> } })\n ?.context?.json?.()) as { message?: string; error?: string } | undefined\n message = String(payload?.message ?? payload?.error ?? '').trim()\n } catch {\n /* no JSON body */\n }\n throw new Error(message || error.message)\n}\n\nexport async function readPaymentReadiness(tenantId?: string): Promise<PaymentReadiness> {\n const answer = await invoke<{ payments: PaymentReadiness }>({ action: 'status' }, tenantId)\n return answer.payments\n}\n\nexport async function openPaymentSetupSession(tenantId?: string): Promise<PaymentSetupSession> {\n return await invoke<PaymentSetupSession>({ action: 'connect' }, tenantId)\n}\n\n/**\n * Is the `pay` action safe to offer in a message template?\n *\n * The sandbox fixture counts, deliberately: a build being dogfooded on sandbox\n * credentials must be able to exercise the whole flow, and the panel is where\n * the \"sandbox\" qualifier is shown. What is refused is a channel with nothing\n * selected behind it, where a Pix button would produce a charge that never opens.\n */\nexport function canOfferPayment(readiness: PaymentReadiness | null): boolean {\n if (!readiness?.ready) return false\n return readiness.mode !== null\n}\n","// Tyxter — WhatsApp as a channel of the inbox, and the first messaging\n// connector on the standard (docs/integrations/CONNECTORS.md).\n//\n// It is the connector with NO connect form at all, and that is the whole design\n// rather than an omission. FayaLabs holds one Tyxter project per product and\n// one dashboard key with it; a tenant gets WhatsApp by agreeing to use it, not\n// by going to find a key that was never issued to them. So `fields` is empty,\n// no credential sink is involved, and connecting writes one thing: the\n// connections row that says this tenant switched it on. The key is redeemed\n// server-side, per call, by the edge functions that land in WP3–WP6.\n//\n// `authKind: 'api-key'` still, and not 'oauth': Tyxter has no consent screen and\n// no app to install, so declaring OAuth would ship a button with no flow behind\n// it (the Bling failure named in the standard).\n//\n// No SQL of its own for the CONNECTION — that is a connections row (029).\n// The table this plugin does add, plg_conversations_channels, is not connection\n// state: it is which phone number a message leaves by, which outlives any one\n// connector and is read by the inbox itself.\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport { ExternalLink, Loader2 } from 'lucide-react'\nimport { Button, Input, toast } from '@fayz-ai/ui'\nimport {\n connectionRuns,\n connectionStatus,\n createConnectionStore,\n useActiveTenantId,\n type ConnectorDefinition,\n describeError,\n} from '@fayz-ai/core'\nimport {\n CHANNEL_CLAIM_TIMELINE,\n canClaimDedicated,\n findDedicatedChannel,\n findFallbackChannel,\n isPendingChannelStatus,\n listMessagingChannels,\n type MessagingChannelAccount,\n type MessagingChannelStatus,\n} from '../../data/channels'\nimport {\n claimDedicatedNumber,\n metaRegistrationHandoff,\n refreshDedicatedNumbers,\n type MetaRegistrationHandoff,\n} from './data'\nimport {\n canOfferPayment,\n openPaymentSetupSession,\n readPaymentReadiness,\n type PaymentReadiness,\n} from '../../data/payment-preflight'\n\nexport const TYXTER_CONNECTOR_ID = 'tyxter'\n\n/**\n * Four seconds.\n *\n * Nobody is staring at a spinner here — the caller is an automation reacting to\n * a booking — but the budget is what stops a slow provider from holding the\n * automation executor's worker while the next twenty events queue behind it.\n * Tyxter answers `POST /v1/messages` with a 202 and does the delivery\n * asynchronously, so the call being timed is an accept, not a send.\n */\nexport const TYXTER_LATENCY_BUDGET_MS = 4000\n\n// One account per tenant: the platform's project is the same one for everybody,\n// and what the row records is consent, so there is no instance to key on.\nconst store = createConnectionStore(TYXTER_CONNECTOR_ID)\n\nconst KIND_LABEL: Record<MessagingChannelAccount['kind'], string> = {\n fallback: 'Número da plataforma',\n dedicated: 'Número dedicado',\n}\n\nconst STATUS_LABEL: Record<MessagingChannelAccount['status'], string> = {\n requested: 'Solicitado',\n provisioning: 'Em preparação',\n provisioned: 'Preparado',\n verifying: 'Em verificação',\n active: 'Ativo',\n failed: 'Falhou',\n released: 'Liberado',\n disconnected: 'Desconectado',\n}\n\n/** How long between polls while a claim is on its way. */\nconst POLL_INTERVAL_MS = 5000\n\n/**\n * The lifecycle, drawn.\n *\n * Five steps and only the last one sends. Drawn as a list rather than a single\n * badge because the wait is the thing being explained: a person who asked for a\n * phone line and sees \"Em preparação\" for two minutes needs to know how many\n * steps are left, not just which one is current.\n */\nfunction ClaimTimeline({ status }: { status: MessagingChannelStatus }) {\n if (status === 'failed' || status === 'released' || status === 'disconnected') {\n return (\n <p className=\"text-xs text-destructive\">\n {status === 'failed'\n ? 'O pedido não foi concluído. Você pode tentar de novo.'\n : `Este número saiu do ar (${STATUS_LABEL[status]}).`}\n </p>\n )\n }\n const current = CHANNEL_CLAIM_TIMELINE.indexOf(status)\n return (\n <ol className=\"space-y-1\">\n {CHANNEL_CLAIM_TIMELINE.map((step, index) => {\n const done = current > index\n const now = current === index\n return (\n <li\n key={step}\n className={`flex items-center gap-2 text-xs ${\n now ? 'font-medium text-foreground' : done ? 'text-muted-foreground' : 'text-muted-foreground/60'\n }`}\n >\n <span aria-hidden className={`h-1.5 w-1.5 rounded-full ${done || now ? 'bg-primary' : 'bg-border'}`} />\n {STATUS_LABEL[step]}\n {now && status !== 'active' && <Loader2 className=\"h-3 w-3 animate-spin\" />}\n </li>\n )\n })}\n </ol>\n )\n}\n\n/**\n * The handoff a machine cannot make.\n *\n * A rented number is not a registered one: Meta has never seen it, and WhatsApp\n * Embedded Signup is a browser window a person clicks through — the provider's\n * own connect endpoint refuses a Salvy number with `meta_registration_required`\n * and says there is no headless equivalent. So this is the honest end of the\n * flow, and it is prominent rather than tucked away, because a claim that stops\n * here without saying so looks like a claim that worked.\n */\nfunction MetaRegistrationCard({ handoff }: { handoff: MetaRegistrationHandoff }) {\n return (\n <div className=\"space-y-2 rounded-md border border-primary/40 bg-primary/5 p-3\">\n <p className=\"text-xs font-medium text-foreground\">Falta liberar o número na Meta</p>\n <p className=\"text-xs text-muted-foreground\">\n O número já é seu, mas ainda não pode enviar: a Meta exige que alguém conclua o cadastro do\n WhatsApp numa janela do navegador. É rápido, e só precisa ser feito uma vez.\n </p>\n <Button asChild size=\"sm\">\n <a href={handoff.url} target=\"_blank\" rel=\"noopener noreferrer\">\n Concluir cadastro na Meta\n <ExternalLink className=\"ml-1.5 h-3.5 w-3.5\" />\n </a>\n </Button>\n {handoff.source === 'default' && (\n <p className=\"text-[11px] text-muted-foreground\">\n Confira se a conta aberta no navegador é a certa antes de concluir.\n </p>\n )}\n </div>\n )\n}\n\n/**\n * Can the customer pay inside the conversation, and if not, what has to happen?\n *\n * The answer is not in this pool. It is at the provider, behind the platform's\n * key, so `tyxter-payment-preflight` asks and this renders the verdict. Three\n * states and they are deliberately not two:\n *\n * ready, real a payment connection is selected. Nothing to do.\n * ready, sandbox charges open and settle, with money that is not real.\n * Shown as ready WITH the word \"sandbox\", because a green\n * tick over a fixture is discovered on the day of the first\n * real charge.\n * not ready the handoff button, which opens a session at the provider\n * rather than linking to a dashboard the merchant then has\n * to navigate.\n *\n * The credentials are typed at the provider and never reach this app. That is\n * the accepted redundancy with the app's own AbacatePay connector, and it is\n * also the reason this panel has no form: a secret that never enters the\n * product is one the product cannot leak.\n */\nfunction TyxterPaymentsPanel() {\n const [readiness, setReadiness] = useState<PaymentReadiness | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(true)\n const [handoff, setHandoff] = useState<string | null>(null)\n const [opening, setOpening] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n void readPaymentReadiness()\n .then((value) => { if (!cancelled) setReadiness(value) })\n .catch((caught: unknown) => {\n if (!cancelled) setError(describeError(caught, 'Não deu para verificar agora.'))\n })\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [])\n\n const connect = async () => {\n setOpening(true)\n setError(null)\n try {\n const session = await openPaymentSetupSession()\n setHandoff(session.setupUrl)\n // Opened by the merchant and not by us: a popup fired from an async\n // callback is the one a browser blocks, and a blocked popup reads as a\n // button that does nothing.\n } catch (caught) {\n setError(describeError(caught, 'Não deu para abrir a configuração.'))\n } finally {\n setOpening(false)\n }\n }\n\n const ready = canOfferPayment(readiness)\n\n return (\n <div className=\"space-y-3 border-t pt-4\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Pagamento no WhatsApp</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Com isso ligado, o cliente recebe o Pix na própria conversa e o agendamento fica marcado\n como pago sozinho.\n </p>\n </div>\n\n {loading && <p className=\"text-xs text-muted-foreground\">Verificando…</p>}\n\n {!loading && ready && (\n <p className=\"text-xs text-foreground\">\n <span className=\"font-medium text-emerald-600\">Pronto para cobrar</span>\n {readiness?.sandbox && (\n <span className=\"ml-2 rounded bg-amber-100 px-1.5 py-0.5 text-[11px] font-medium text-amber-800\">\n sandbox — o dinheiro não é real\n </span>\n )}\n </p>\n )}\n\n {!loading && !ready && (\n <div className=\"space-y-2\">\n <p className=\"text-xs text-muted-foreground\">\n Ainda não dá para cobrar por aqui. A conta de pagamento é configurada na Tyxter, em uma\n página deles — a sua chave não passa por este app.\n {readiness?.reason ? ` (${readiness.reason})` : ''}\n </p>\n {handoff ? (\n <a\n href={handoff}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-block rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n Abrir a configuração de pagamento →\n </a>\n ) : (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => { void connect() }} disabled={opening}>\n {opening ? 'Abrindo…' : 'Configurar pagamento'}\n </Button>\n )}\n </div>\n )}\n\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n )\n}\n\n/**\n * Which numbers this tenant sends by, and the button that gets it one of its own.\n *\n * ── Why this polls ──────────────────────────────────────────────────────────\n * Verified against the provider's sandbox on 2026-08-24: provisioning a number\n * walked requested → provisioned → verifying → active in about a second and\n * emitted ZERO `phone_number.*` webhooks. The deliverable events are verified /\n * disconnected / released / quality_changed / messaging_limit_*, and none of\n * them fired. So the webhook (WP4) is not the mechanism that advances a claim —\n * asking is, and this panel asks every few seconds while the row is pending and\n * stops the moment it is not.\n */\nfunction TyxterExtraPanel() {\n const tenantId = useActiveTenantId()\n const [channels, setChannels] = useState<MessagingChannelAccount[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [ddd, setDdd] = useState('')\n const [claiming, setClaiming] = useState(false)\n const [handoff, setHandoff] = useState<MetaRegistrationHandoff | null>(null)\n const mounted = useRef(true)\n\n useEffect(() => {\n mounted.current = true\n return () => { mounted.current = false }\n }, [])\n\n const load = useCallback(async () => {\n try {\n const rows = await listMessagingChannels({ provider: TYXTER_CONNECTOR_ID, channel: 'whatsapp' })\n if (mounted.current) { setChannels(rows); setError(null) }\n } catch {\n if (mounted.current) setError('Não conseguimos ler os números agora.')\n }\n }, [])\n\n useEffect(() => { void load() }, [load])\n\n const dedicated = channels ? findDedicatedChannel(channels, tenantId) : null\n const fallback = channels ? findFallbackChannel(channels) : null\n const pending = dedicated ? isPendingChannelStatus(dedicated.status) : false\n\n // The poll, and the reason it is keyed on `pending`: a screen that keeps\n // asking after the answer arrived is a cost with no reader.\n useEffect(() => {\n if (!pending || !tenantId) return undefined\n const timer = setInterval(() => {\n void refreshDedicatedNumbers(tenantId).then(() => load()).catch(() => {})\n }, POLL_INTERVAL_MS)\n return () => clearInterval(timer)\n }, [pending, tenantId, load])\n\n // The link is asked for once the number exists and while it cannot send.\n // Not during the wait — there is nothing to register yet — and not once the\n // row carries a Meta id, because asking then costs two provider calls per\n // per panel open to be told what the row already said.\n const registered = !!dedicated?.metadata?.meta_phone_number_id\n useEffect(() => {\n if (!tenantId || !dedicated || dedicated.status !== 'active' || registered || handoff) return\n void metaRegistrationHandoff(tenantId)\n .then((answer) => { if (mounted.current) setHandoff(answer.metaRegistration) })\n .catch(() => {})\n }, [tenantId, dedicated, registered, handoff])\n\n const canClaim = !!channels && !!tenantId && canClaimDedicated(channels, tenantId)\n\n async function onClaim() {\n if (!tenantId || !/^\\d{2}$/.test(ddd)) return\n setClaiming(true)\n try {\n const result = await claimDedicatedNumber({ tenantId, ddd })\n setHandoff(result.metaRegistration)\n setDdd('')\n await load()\n toast.success('Número solicitado. Acompanhe aqui o andamento.')\n } catch (caught) {\n toast.error(describeError(caught, 'Não foi possível pedir o número.'))\n } finally {\n if (mounted.current) setClaiming(false)\n }\n }\n\n return (\n <div className=\"space-y-3\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Números</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Por onde as suas mensagens de WhatsApp saem hoje.\n </p>\n </div>\n\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n\n {channels && channels.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">\n Nenhum número configurado ainda. Assim que a plataforma liberar o número compartilhado,\n ele aparece aqui.\n </p>\n )}\n\n {channels && channels.length > 0 && (\n <ul className=\"space-y-2\">\n {channels.map((channel) => (\n <li\n key={channel.id}\n className=\"flex flex-wrap items-baseline justify-between gap-2 rounded-md border bg-muted/30 p-3 text-xs\"\n >\n <span className=\"font-medium text-foreground\">\n {channel.phoneE164 ?? channel.providerNumberId}\n </span>\n <span className=\"text-muted-foreground\">\n {KIND_LABEL[channel.kind]} · {STATUS_LABEL[channel.status]}\n </span>\n </li>\n ))}\n </ul>\n )}\n\n {dedicated && (\n <div className=\"space-y-2 rounded-md border p-3\">\n <p className=\"text-xs font-medium text-foreground\">Seu número dedicado</p>\n <ClaimTimeline status={dedicated.status} />\n {dedicated.status === 'active' && !handoff && (\n <p className=\"text-xs text-muted-foreground\">\n Ativo. As suas mensagens saem por ele, com o seu nome e sem dividir com ninguém.\n </p>\n )}\n </div>\n )}\n\n {handoff && <MetaRegistrationCard handoff={handoff} />}\n\n {canClaim && (\n <div className=\"space-y-2 border-t pt-3\">\n <p className=\"text-xs font-medium text-foreground\">Quer um número só seu?</p>\n <p className=\"text-xs text-muted-foreground\">\n {fallback\n ? 'Hoje as suas mensagens saem pelo número da plataforma, dividido com outros negócios. Um número dedicado sai só com o seu nome, libera os seus próprios modelos de mensagem e tem limite de envio próprio.'\n : 'Um número dedicado sai só com o seu nome e tem limite de envio próprio.'}\n </p>\n <div className=\"flex items-end gap-2\">\n <label className=\"text-xs text-muted-foreground\">\n DDD\n <Input\n value={ddd}\n onChange={(e) => setDdd(e.target.value.replace(/\\D/g, '').slice(0, 2))}\n inputMode=\"numeric\"\n placeholder=\"21\"\n className=\"mt-1 w-20\"\n aria-label=\"DDD do número dedicado\"\n />\n </label>\n <Button size=\"sm\" disabled={claiming || !/^\\d{2}$/.test(ddd)} onClick={() => void onClaim()}>\n {claiming && <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />}\n Solicitar número dedicado\n </Button>\n </div>\n <p className=\"text-[11px] text-muted-foreground\">\n O número é alugado no mês e, depois que chegar, ainda precisa de um cadastro rápido na\n Meta para começar a enviar.\n </p>\n </div>\n )}\n\n <TyxterPaymentsPanel />\n </div>\n )\n}\n\nexport const tyxterConnectorDef: ConnectorDefinition = {\n id: TYXTER_CONNECTOR_ID,\n hostPluginId: 'conversations',\n name: 'Tyxter',\n description:\n 'WhatsApp já pronto: confirmações e lembretes saem por um número da plataforma, e a resposta do cliente cai na sua caixa de entrada.',\n icon: 'MessageCircle',\n logoUrl: 'https://assets.fayz.ai/connectors/tyxter.png',\n category: 'messaging',\n authKind: 'api-key',\n // Sending is in line with the automation that asked for it; the reply, the\n // delivery status and the template approvals arrive later and file runs.\n planes: ['request', 'sync'],\n direction: 'outbound',\n docsUrl: 'https://tyxter.com/docs',\n // A message that does not go out must never take the booking with it. The\n // opposite verdict from a payment gateway, and for the opposite reason.\n latencyBudgetMs: TYXTER_LATENCY_BUDGET_MS,\n onFailure: 'degrade',\n permissions: [\n {\n kind: 'data',\n resource: 'conversation',\n actions: ['read', 'write'],\n reason:\n 'Abrir a conversa do cliente no WhatsApp e mantê-la em dia — é onde a mensagem enviada e a resposta dele ficam juntas.',\n },\n {\n kind: 'data',\n resource: 'message',\n actions: ['read', 'write'],\n reason:\n 'Guardar cada mensagem enviada e recebida, com o status que o WhatsApp devolve (enviada, entregue, lida).',\n },\n {\n kind: 'data',\n resource: 'message_template',\n actions: ['read', 'write'],\n reason:\n 'Ler os modelos de mensagem deste app e guardar o que a Meta respondeu sobre cada um: aprovado, recusado ou pausado.',\n },\n ],\n // No form: the key is the platform's. The connect step says so on its own\n // (`connectors.authorize.nothingToFill`) rather than drawing an empty grid.\n fields: [],\n invokedAt: [\n {\n key: 'messaging.send',\n label: 'Uma automação dispara e a mensagem sai no WhatsApp do cliente',\n touches: ['conversation', 'message'],\n },\n {\n key: 'conversations.inbound',\n label: 'O cliente responde, e a resposta entra na caixa de entrada',\n plane: 'sync',\n trigger: 'webhook',\n touches: ['conversation', 'message'],\n },\n {\n key: 'messaging.template_sync',\n label: 'Os modelos de mensagem vão para aprovação da Meta e o resultado volta para cá',\n plane: 'sync',\n trigger: 'scheduled',\n touches: ['message_template'],\n },\n ],\n howItSyncs: [\n 'As mensagens saem por um número de WhatsApp da plataforma, que já vem pronto — você não cadastra chave nenhuma nem precisa de um chip só seu.',\n 'Como esse número é dividido com outros negócios, o nome do seu vai escrito no começo da mensagem, e só modelos já aprovados pela Meta podem sair por ele.',\n 'Se você pedir um número dedicado, ele passa a ser o remetente assim que ficar ativo — aí a mensagem sai só com o seu nome e nada mais é dividido.',\n 'A resposta do cliente volta para Conversas em segundos, e botões como Confirmar e Cancelar já atualizam o agendamento sozinhos.',\n ],\n ...connectionStatus(\n TYXTER_CONNECTOR_ID,\n (connection) => ({ connected: !!connection?.active, plane: 'request' }),\n { store: () => store },\n ),\n ...connectionRuns(store),\n // Nothing to receive: the hub split out a credential half that does not exist\n // for this connector, so `values` is empty and consent is the whole act.\n saveConnection: async () => {\n await store.save({ active: true })\n },\n disconnect: () => store.disconnect(),\n disconnectNote:\n 'Desconectar para de enviar e de receber mensagens no WhatsApp. As conversas que já existem continuam aqui.',\n ExtraPanel: TyxterExtraPanel,\n}\n","import { defineSettingsTab } from '@fayz-ai/admin'\nimport { tl } from '@fayz-ai/core'\n\nexport const conversationsV1SettingsTabs = [\n defineSettingsTab({\n id: 'conversations-atendeai',\n label: 'AtendeAI',\n icon: 'Bot',\n section: 'communication',\n requiresFacet: 'atendeai',\n pending: true,\n defaults: {\n 'atendeai.assistant_name': 'Assistente', 'atendeai.tone': 'friendly',\n 'atendeai.ai_disclosure': true, 'atendeai.max_messages_per_conversation': 30, 'atendeai.escalation_timeout_minutes': 30,\n },\n sections: [\n { title: tl('General', 'Geral'), fields: [\n { key: 'atendeai.assistant_name', type: 'string', label: tl('Assistant name', 'Nome do assistente') },\n { key: 'atendeai.ai_disclosure', type: 'boolean', label: tl('Say it is an AI', 'Avisar que é uma inteligência artificial') },\n ] },\n { title: tl('Personality', 'Personalidade'), fields: [\n { key: 'atendeai.tone', type: 'select', label: tl('Tone', 'Tom'), options: [\n { value: 'friendly', label: tl('Friendly', 'Amigável') }, { value: 'formal', label: tl('Formal', 'Formal') }, { value: 'casual', label: tl('Casual', 'Descontraído') },\n ] },\n { key: 'atendeai.greeting_message', type: 'string', label: tl('Greeting', 'Mensagem de boas-vindas') },\n { key: 'atendeai.farewell_message', type: 'string', label: tl('Farewell', 'Mensagem de despedida') },\n { key: 'atendeai.handoff_message', type: 'string', label: tl('When handing over to a person', 'Ao passar para uma pessoa') },\n { key: 'atendeai.out_of_scope_message', type: 'string', label: tl('When the question is out of scope', 'Quando a pergunta foge do escopo') },\n ] },\n { title: tl('Limits', 'Limites'), fields: [\n { key: 'atendeai.max_messages_per_conversation', type: 'number', min: 1, max: 200, label: tl('Max AI messages per conversation', 'Máximo de mensagens da IA por conversa') },\n { key: 'atendeai.escalation_timeout_minutes', type: 'number', min: 1, max: 1440, label: tl('Minutes before handing over', 'Minutos até passar para uma pessoa') },\n ] },\n ],\n }),\n]\n","// ---------------------------------------------------------------------------\n// Campanhas, do lado do navegador.\n//\n// A leitura é direta (RLS por inquilino); o DISPARO passa pela função de borda,\n// porque é lá que a credencial mora e é lá que o ritmo é respeitado. O navegador\n// nunca fala com o Tyxter nem com o Evolution.\n// ---------------------------------------------------------------------------\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport type { ProviderId } from './providers'\n\nexport interface CampaignTemplate {\n id: string\n name: string\n language: string\n category: string\n body: string\n /** Os nomes das variáveis, na ordem de {{1}}, {{2}}. A Meta entende posição;\n * gente entende nome — e a tela pede \"cargo\", não \"variável 3\". */\n variables: string[]\n provider: string | null\n status: string\n statusDetail: string | null\n}\n\nexport interface CampaignProgress {\n campaignId: string\n name: string\n status: 'draft' | 'scheduled' | 'running' | 'paused' | 'done' | 'cancelled'\n pausedReason: string | null\n provider: string | null\n total: number\n queued: number\n sending: number\n sent: number\n delivered: number\n read: number\n replied: number\n failed: number\n skipped: number\n /** Abaixo de 30% a prática diz que o risco de banimento sobe. Fica na tela. */\n replyRate: number | null\n firstSentAt: string | null\n lastSentAt: string | null\n}\n\nexport interface DispatchResult {\n campaignId: string\n provider?: ProviderId\n sent: number\n remaining: number | null\n failures?: Array<{ to: string; code: string; message: string }>\n paused?: string\n skipped?: boolean\n reason?: string\n}\n\nfunction client() {\n const c = getSupabaseClientOptional() as any\n if (!c) throw new Error('Supabase não inicializado')\n return c\n}\n\nfunction tenant(): string {\n const t = getActiveTenantId()\n if (!t) throw new Error('Nenhuma casa ativa')\n return t\n}\n\nexport const campaignsApi = {\n async templates(): Promise<CampaignTemplate[]> {\n const { data, error } = await client()\n .from('plg_conversations_templates')\n .select('id, name, language, category, body, variables, provider, status, status_detail')\n .eq('tenant_id', tenant()).order('name')\n if (error) throw new Error(error.message)\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, name: r.name, language: r.language, category: r.category,\n body: r.body, variables: r.variables ?? [], provider: r.provider,\n status: r.status, statusDetail: r.status_detail ?? null,\n }))\n },\n\n async saveTemplate(t: { id?: string; name: string; body: string; variables?: string[]; language?: string; category?: string }) {\n const row = {\n tenant_id: tenant(), name: t.name, body: t.body,\n variables: t.variables ?? [], language: t.language ?? 'pt_BR',\n category: t.category ?? 'MARKETING', updated_at: new Date().toISOString(),\n }\n const q = t.id\n ? client().from('plg_conversations_templates').update(row).eq('id', t.id)\n : client().from('plg_conversations_templates').insert(row)\n const { error } = await q\n if (error) throw new Error(error.message)\n },\n\n async list(): Promise<CampaignProgress[]> {\n const { data, error } = await client()\n .from('v_conversations_campaign_progress')\n .select('*').eq('tenant_id', tenant())\n if (error) throw new Error(error.message)\n return ((data ?? []) as any[]).map((r) => ({\n campaignId: r.campaign_id, name: r.name, status: r.status,\n pausedReason: r.paused_reason ?? null, provider: r.provider,\n total: Number(r.total ?? 0), queued: Number(r.queued ?? 0),\n sending: Number(r.sending ?? 0), sent: Number(r.sent ?? 0),\n delivered: Number(r.delivered ?? 0), read: Number(r.read ?? 0),\n replied: Number(r.replied ?? 0), failed: Number(r.failed ?? 0),\n skipped: Number(r.skipped ?? 0),\n replyRate: r.reply_rate == null ? null : Number(r.reply_rate),\n firstSentAt: r.first_sent_at ?? null, lastSentAt: r.last_sent_at ?? null,\n }))\n },\n\n /** Cria a campanha e enfileira os destinatários.\n *\n * `ON CONFLICT DO NOTHING` via upsert: o índice único (campanha, telefone,\n * rodada) é quem impede o disparo duplo, e não uma checagem aqui. Dois\n * cliques no botão enfileiram uma vez. */\n async create(input: {\n name: string\n templateId?: string\n provider?: ProviderId\n channelId?: string\n targets: Array<{ phone: string; personId?: string; variables?: Record<string, string> | string[] }>\n }): Promise<string> {\n const tenantId = tenant()\n const { data: camp, error } = await client()\n .from('plg_conversations_campaigns')\n .insert({\n tenant_id: tenantId, name: input.name,\n template_id: input.templateId ?? null,\n provider: input.provider ?? null,\n channel_id: input.channelId ?? null,\n status: 'draft',\n })\n .select('id').single()\n if (error) throw new Error(error.message)\n\n const rows = input.targets\n .map((t) => ({\n tenant_id: tenantId, campaign_id: camp.id,\n phone_e164: String(t.phone).replace(/\\D/g, ''),\n person_id: t.personId ?? null,\n variables: t.variables ?? {},\n }))\n .filter((r) => r.phone_e164.length >= 10)\n\n // Em blocos: o PostgREST tem teto por requisição, e uma lista de 300 leads\n // numa inserção só volta truncada sem dizer que truncou.\n for (let i = 0; i < rows.length; i += 200) {\n const { error: e } = await client()\n .from('plg_conversations_campaign_targets')\n .upsert(rows.slice(i, i + 200), { onConflict: 'campaign_id,phone_e164,rotation', ignoreDuplicates: true })\n if (e) throw new Error(e.message)\n }\n return camp.id as string\n },\n\n async setStatus(campaignId: string, status: CampaignProgress['status']) {\n const patch: Record<string, unknown> = { status, updated_at: new Date().toISOString() }\n if (status === 'running') { patch.started_at = new Date().toISOString(); patch.paused_reason = null }\n const { error } = await client()\n .from('plg_conversations_campaigns').update(patch).eq('id', campaignId)\n if (error) throw new Error(error.message)\n },\n\n /** Um lote. Quem chama repete até `remaining` chegar a zero — o arrendamento\n * de cinco minutos é o que impede duas chamadas de mandarem o mesmo. */\n async dispatch(campaignId: string, limit?: number): Promise<DispatchResult> {\n const { data, error } = await client().functions.invoke('conversations-provider', {\n body: { tenantId: tenant(), action: 'dispatch', campaignId, limit },\n })\n if (error) {\n const detail = (await error.context?.json?.().catch(() => null)) as { message?: string } | null\n throw new Error(detail?.message ?? error.message)\n }\n if ((data as any)?.error) throw new Error((data as any).message ?? (data as any).error)\n return data as DispatchResult\n },\n}\n","import React from 'react'\nimport { InboxWatcher } from './components/InboxWatcher'\nimport type { EntityDef, PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { lazyComponent, getActiveTenantId, getSupabaseClientOptional, registerTranslations } from '@fayz-ai/core'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport type { ResolvedConversationsConfig } from './context'\nimport type { ConversationsProvider } from './data/types'\nimport { createMockConversationsProvider } from './data/mock'\nimport { createSupabaseConversationsProvider } from './data/supabase'\nimport { createConversationsStore } from './store'\nimport { conversationsLocales } from './locales'\nimport { createConversationsDashboardWidgets } from './views/dashboardWidgets'\nimport { buildConversationsOnboarding } from './lib/onboarding'\nimport { tyxterConnectorDef } from './integrations/tyxter/connectorDef'\nimport { MIGRATIONS } from './migrations'\n\n// ---------------------------------------------------------------------------\n// @fayz-ai/plugin-conversations — the GoHighLevel \"Conversations\" equivalent:\n// one omni-channel inbox (SMS / WhatsApp / Instagram / Email / Web chat).\n// Universal plugin — reusable by any vertical (beauty, resto, agency…).\n//\n// Supabase-backed (plg_conversations / plg_conversation_messages, tenant-scoped\n// via RLS) when a client is registered; a persisted mock inbox otherwise.\n// WhatsApp arrives through the Tyxter connector declared below; the other\n// channels still deliver inbound rows out-of-band, and this plugin stays the\n// read/compose surface for all of them.\n// ---------------------------------------------------------------------------\n\nexport interface ConversationsPluginOptions {\n navPosition?: number\n navSection?: 'main' | 'secondary' | 'settings'\n navLabel?: string\n scope?: PluginScope\n verticalId?: VerticalId\n dataProvider?: ConversationsProvider\n\n /**\n * `people.kind` for contacts created from the compose modal's picker. Each\n * vertical names its people differently (beauty 'client', agency 'lead'),\n * hence a knob rather than a hardcoded value. Default: 'contact'.\n */\n contactKind?: string\n /** Custom search source for the picker. Defaults to the person archetype lookup. */\n contactLookup?: EntityLookup\n /**\n * The app's contact entity, same definition its registry page uses. \"Create\"\n * in the picker opens THAT form. Without it the picker searches only.\n */\n contactEntityDef?: EntityDef\n}\n\nfunction createSafeProvider(): ConversationsProvider {\n // Real data when a Supabase client is registered; mock inbox otherwise.\n // Resolution is LAZY (per call): createConversationsPlugin runs at module\n // scope in the app config, BEFORE the Supabase client is registered — an\n // eager check here would capture the mock forever even on live backends.\n let real: ConversationsProvider | null = null\n let mock: ConversationsProvider | null = null\n const resolve = (): ConversationsProvider => {\n if (getSupabaseClientOptional()) {\n real ??= createSupabaseConversationsProvider({ tenantId: () => getActiveTenantId() })\n return real\n }\n mock ??= createMockConversationsProvider({ tenantId: () => getActiveTenantId() })\n return mock\n }\n return {\n listConversations: (...a) => resolve().listConversations(...a),\n getMessages: (...a) => resolve().getMessages(...a),\n sendMessage: (...a) => resolve().sendMessage(...a),\n markRead: (...a) => resolve().markRead(...a),\n setStatus: (...a) => resolve().setStatus(...a),\n createConversation: (...a) => resolve().createConversation(...a),\n }\n}\n\nexport function createConversationsPlugin(options?: ConversationsPluginOptions): PluginManifest {\n registerTranslations(conversationsLocales)\n const provider = options?.dataProvider ?? createSafeProvider()\n const store = createConversationsStore(provider)\n\n const config: ResolvedConversationsConfig = {\n contactKind: options?.contactKind ?? 'contact',\n contactLookup: options?.contactLookup,\n contactEntityDef: options?.contactEntityDef,\n }\n\n const dashboardWidgets = createConversationsDashboardWidgets({ store, config })\n\n const PageComponent: React.ComponentType<unknown> = () =>\n React.createElement(ConversationsPage, { store, config })\n PageComponent.displayName = 'ConversationsPage'\n\n return {\n id: 'conversations',\n defaultAgentRole: 'frontdesk',\n name: options?.navLabel ?? 'Conversations',\n icon: 'MessageCircle',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n dependencies: [],\n declaredFeatures: [{ id: 'conversations', label: 'Conversations', group: 'Engage' }],\n // Recurring monthly quota — counts conversation threads created this month.\n declaredLimits: [\n { key: 'conversations_month', label: 'Conversations this month', table: 'plg_conversations', period: 'month' },\n ],\n // SEM linha de rail para `/conversations`. A caixa de entrada subiu para a\n // faixa do aplicativo, como ícone com a conta do que espera resposta — ver\n // o widget `conversations-inbox` abaixo. Ela não é um destino como o\n // Financeiro: é um estado que se lê de canto de olho, e no rail a conta\n // ficava escondida atrás de um menu que recolhe.\n //\n // E SEM CAMPANHAS NEM TEMPLATES. As duas telas foram removidas — não\n // escondidas: elas tomavam duas linhas de rail num plugin que declara, na\n // nota acima, que nem a própria caixa de entrada merece uma. Ficavam\n // acima de Encontros, CRM e Financeiro em toda conta com conversas\n // ligadas, e a segunda cópia que apareceu embaixo de Estoque foi o sinal\n // de que ninguém sabia mais de onde elas vinham.\n //\n // O MAQUINÁRIO FICA: `campaignsApi`, `plg_conversations_campaigns` e o\n // ritmo de disparo continuam, e é por eles que Marketing e Automações\n // mandam mensagem. O que saiu foi a tela solta e o link para ela.\n // AtendeAI does get a rail line, as in V1: whoever runs the AI follows it\n // all day. Offered to every account — off, the page is the upsell.\n navigation: [\n // AtendeAI é recurso de restaurante (ChefControl): só aparece no vertical\n // 'food'. Uma loja de outro ramo não vê a linha.\n { section: 'main', position: 45, label: 'AtendeAI', route: '/atendeai', icon: 'Bot', before: ['/analytics', '/reports'], verticalId: 'food' as const, permission: { feature: 'conversations', action: 'read' as const } },\n ],\n routes: [\n {\n path: '/atendeai',\n component: AtendeAIPage as unknown as React.ComponentType<unknown>,\n permission: { feature: 'conversations', action: 'read' as const },\n },\n {\n path: '/conversations',\n component: PageComponent,\n fullBleed: true,\n permission: { feature: 'conversations', action: 'read' as const },\n },\n ],\n // In the shell's header, next to the bell (notifications sit at 100): both\n // say \"something is waiting on you\", so they sit side by side. Header\n // controls render outside the route switch, so the watcher's sound and\n // count survive navigation.\n headerControls: [{\n id: 'conversations-inbox',\n component: (() => {\n const W: React.FC = () => React.createElement(InboxWatcher, {\n label: options?.navLabel ?? 'Conversations',\n store,\n config,\n inHeader: true,\n })\n W.displayName = 'InboxButton'\n return W as unknown as React.ComponentType<unknown>\n })(),\n // After the cash drawer (90), right before the bell.\n order: 95,\n }],\n dashboardWidgets,\n events: [\n { name: 'conversations.message.received', description: 'An inbound message arrived on any channel' },\n { name: 'conversations.message.sent', description: 'An outbound message was sent' },\n {\n // Emitted server-side by plg_emit_event, from the tyxter-webhook's\n // payment handler — the browser never sees this write, which is the\n // whole reason packages/db/migrations/027 exists.\n name: 'conversations.payment_received',\n title: 'Pagamento recebido na conversa',\n description: 'O cliente pagou uma cobrança enviada dentro da conversa',\n trigger: 'Quando o provedor confirma o pagamento de uma cobrança aberta no chat',\n icon: 'BadgeDollarSign',\n fields: [\n { name: 'amount', label: 'Valor', type: 'money', example: 'R$ 120,00' },\n { name: 'amount_cents', label: 'Valor em centavos', type: 'number', example: '12000' },\n { name: 'currency', label: 'Moeda', type: 'string', example: 'BRL' },\n { name: 'description', label: 'Descrição da cobrança', type: 'string', example: 'Corte + Escova' },\n { name: 'channel', label: 'Canal', type: 'string', example: 'whatsapp' },\n { name: 'provider', label: 'Provedor', type: 'string', example: 'tyxter' },\n // The subject is the BOOKING, not the charge: an automation reacting\n // to this needs the thing that was paid for, and the charge id is the\n // audit trail beside it.\n { name: 'subject_type', label: 'Tipo do registro', type: 'string', example: 'booking' },\n { name: 'subject_id', label: 'Registro', type: 'id', example: '9f1c…' },\n { name: 'payment_request_id', label: 'Cobrança', type: 'id', example: '3ab2…' },\n ],\n },\n ],\n aiTools: [\n {\n id: 'conversations.list-threads',\n name: 'listConversations',\n description: 'Lists open conversations across all channels, optionally filtered by channel.',\n icon: 'MessageCircle',\n mode: 'read' as const,\n category: 'Conversations',\n parameters: {\n type: 'object' as const,\n properties: {\n channel: {\n type: 'string' as const,\n enum: ['all', 'sms', 'whatsapp', 'instagram', 'email', 'webchat'],\n },\n },\n },\n suggestions: [\n { label: 'Mostre as conversas não lidas' },\n { label: 'Chegou mensagem nova no WhatsApp?' },\n ],\n permission: { feature: 'conversations', action: 'read' as const },\n },\n {\n id: 'conversations.send-message',\n name: 'sendMessage',\n description: 'Sends a reply in a conversation thread.',\n icon: 'Send',\n mode: 'persist' as const,\n category: 'Conversations',\n parameters: {\n type: 'object' as const,\n properties: {\n conversationId: { type: 'string' as const, description: 'Conversation id' },\n body: { type: 'string' as const, description: 'Message body' },\n },\n required: ['conversationId', 'body'],\n },\n permission: { feature: 'conversations', action: 'create' as const },\n },\n ],\n // One baseline per unit since #338 — read from the generated barrel\n // rather than listed here, so regenerating the SQL never needs a\n // manifest edit to match.\n migrations: MIGRATIONS.map((entry) => ({\n id: `conversations-${entry.id}`,\n version: '1.0.0',\n sql: entry.sql,\n description:\n 'The whole schema this plugin provisions, as one file: every table, view, function, policy and grant, plus the reference rows it seeds. Replaced the per-change chain in the 1.0.0 squash (#338); the files it collapsed are kept, unapplied, in src/migrations.archive/.',\n })),\n functions: [\n {\n slug: 'tyxter-webhook',\n // PUBLIC, and the only function in this plugin that is. The caller is\n // Tyxter's infrastructure, which has no Supabase session and never\n // will — so the gateway check is off and the HMAC signature over\n // `${timestamp}.${rawBody}` IS the authentication.\n ingress: 'none',\n verifyJwt: false,\n // NAMES only. TYXTER_WEBHOOK_SECRET is the endpoint signing secret,\n // returned exactly ONCE by POST /v1/webhook-endpoints and stored as a\n // pool secret by the provisioning script — it is per-endpoint, which is\n // why it can live in the pool while the API key cannot.\n secrets: [\n 'TYXTER_WEBHOOK_SECRET',\n 'TYXTER_API_BASE_URL',\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n ],\n },\n {\n slug: 'tyxter-template-sync',\n // Two callers, neither of them the outside world: an operator with a\n // Supabase JWT, and an ops script with TYXTER_SYNC_SECRET. The second\n // cannot present a JWT, so the gateway check has to be off and the\n // function authenticates itself.\n ingress: 'none',\n verifyJwt: false,\n // NAMES only. The Tyxter key is NOT here and could not be: a Supabase\n // secret is per-POOL and the key belongs to the platform's project — it\n // is redeemed per run from the vault, which is what the last three are for.\n secrets: [\n 'TYXTER_API_BASE_URL',\n 'TYXTER_SYNC_SECRET',\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n ],\n },\n {\n slug: 'tyxter-payment-preflight',\n // verify_jwt TRUE — the only function in this wave with a human caller\n // and nothing else. An operator looking at the connector panel has a\n // Supabase session; there is no clock and no ops script here, so the\n // gateway's own check is left on and membership is checked on top of it.\n ingress: 'none',\n verifyJwt: true,\n // NAMES only. The browser cannot ask Tyxter anything — the key is the\n // platform's — which is the whole reason this function exists.\n secrets: [\n 'TYXTER_API_BASE_URL',\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n ],\n },\n ],\n // The settings screen exists so the connector below can be REACHED: the\n // Integrations tab is drawn by PluginSettingsPanel, so a plugin with a\n // connector and no settings route ships a connector nobody can open.\n facets: [\n { id: 'atendeai', label: 'AtendeAI', description: 'A inteligência artificial que responde no WhatsApp.' },\n ],\n settings: [\n ...conversationsV1SettingsTabs,\n {\n id: 'conversations',\n label: 'Conversas',\n icon: 'MessageCircle',\n component: ConversationsSettingsTab as React.ComponentType<unknown>,\n order: 30,\n permission: { feature: 'conversations', action: 'read' as const },\n },\n ],\n onboarding: { program: buildConversationsOnboarding() },\n // WhatsApp through Tyxter. Declared here because this plugin IS the inbox\n // the messages land in — the connector configures inside Conversas.\n connectors: [tyxterConnectorDef],\n locales: conversationsLocales,\n }\n}\n\nexport type { ConversationsProvider } from './data/types'\nexport type { Conversation, Message, Channel, MessageDirection, CreateConversationInput } from './types'\nexport { isWaitingOnUs } from './types'\nexport { createMockConversationsProvider, type MockConversationsConfig } from './data/mock'\nexport {\n createSupabaseConversationsProvider,\n type SupabaseConversationsConfig,\n} from './data/supabase'\n// The automations template editor gates its `pay` action on this, so it has to\n// leave the plugin — see PaymentReadiness for why `ready` alone is not the test.\nexport {\n readPaymentReadiness,\n openPaymentSetupSession,\n canOfferPayment,\n PAYMENT_PREFLIGHT_FUNCTION,\n type PaymentReadiness,\n type PaymentActiveMode,\n type PaymentSetupSession,\n} from './data/payment-preflight'\nexport {\n listMessagingChannels,\n type MessagingChannelAccount,\n type MessagingChannelKind,\n type MessagingChannelStatus,\n type ListMessagingChannelsOptions,\n} from './data/channels'\n// Exported so a bespoke admin can render the connector without mounting the\n// whole plugin — the same reason plugin-shop exports its definitions.\nexport {\n tyxterConnectorDef,\n TYXTER_CONNECTOR_ID,\n TYXTER_LATENCY_BUDGET_MS,\n} from './integrations/tyxter/connectorDef'\nimport { conversationsV1SettingsTabs } from './settings/v1-settings'\n\n// Code loads when it is first drawn, not with the app. Pages use React.lazy\n// (the shell's route boundary shows the page skeleton); anything that may\n// render elsewhere uses lazyComponent, which carries its own boundary.\nconst ConversationsPage = React.lazy(() => import('./views/ConversationsPage').then((m) => ({ default: m.ConversationsPage })))\nconst AtendeAIPage = React.lazy(() => import('./views/AtendeAIPage').then((m) => ({ default: m.AtendeAIPage })))\nconst ConversationsSettingsTab = lazyComponent(() => import('./settings/ConversationsSettings').then((m) => m.ConversationsSettingsTab))\n\n// A campanha e os provedores, exportados para que outro plugin possa criar uma\n// campanha sem montar a caixa de entrada inteira. É o que deixa a lista de\n// leads do CRM oferecer \"Enviar WhatsApp\" carregando este módulo sob demanda:\n// um import estático faria a lista quebrar num app onde este plugin não está.\nexport { campaignsApi } from './data/campaigns'\nexport type { CampaignProgress, CampaignTemplate, DispatchResult } from './data/campaigns'\nexport { providersApi } from './data/providers'\nexport type { ProviderId, ProviderRow, ProviderNumber, ProviderTemplate, ProviderCapabilities } from './data/providers'\nexport { WhatsAppProviders } from './settings/WhatsAppProviders'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/integrations/evolution/connectorDef.tsx","../src/components/InboxWatcher.tsx","../src/data/accents.ts","../src/data/mock.ts","../src/data/supabase.ts","../src/store.ts","../src/locales/en.ts","../src/locales/pt-BR.ts","../src/locales/index.ts","../src/views/dashboardWidgets.tsx","../src/lib/onboarding.ts","../src/integrations/tyxter/data.ts","../src/data/payment-preflight.ts","../src/integrations/tyxter/connectorDef.tsx","../src/settings/v1-settings.ts","../src/data/campaigns.ts","../src/index.ts"],"names":["client","getSupabaseClientOptional","useEffect","jsx","invoke","tenant","useState","useActiveTenantId","useRef","useCallback","getActiveTenantId","store","React"],"mappings":"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","file":"index.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Evolution API — WhatsApp through the store's own number, on the connectors\n// list like any other connector.\n//\n// It used to exist only inside Configurações → Conversas → Conectores, so a\n// merchant who went looking for WhatsApp in Configurações → Conectores did not\n// find it. The setup itself stays where it was built: the provider card (URL,\n// key, instance, Testar, Parear, Números) is the ExtraPanel here, so there is\n// one form and one way to pair, reached from both screens.\n// ---------------------------------------------------------------------------\n\nimport React from 'react'\nimport type { ConnectorDefinition, ConnectorStatus } from '@fayz-ai/core'\nimport { providersApi } from '../../data/providers'\nimport { WhatsAppProviders } from '../../settings/WhatsAppProviders'\n\nexport const EVOLUTION_CONNECTOR_ID = 'evolution'\n\nasync function evolutionStatus(): Promise<ConnectorStatus> {\n const row = (await providersApi.list()).find((r) => r.provider === EVOLUTION_CONNECTOR_ID)\n if (!row || row.status === 'unconfigured') return { connected: false }\n if (row.status === 'connected') {\n return {\n connected: true,\n plane: 'request',\n detail: row.isActive ? 'Valendo agora' : 'Conectado, mas outro provedor está valendo',\n }\n }\n // Configured but not paired, or the session dropped: say what to do.\n return {\n connected: false,\n detail: row.status === 'error'\n ? (row.statusDetail ?? 'A instância respondeu com erro')\n : 'Configurado — falta parear o número pelo QR',\n }\n}\n\nfunction EvolutionPanel() {\n return <WhatsAppProviders only=\"evolution\" />\n}\n\nexport const evolutionConnectorDef: ConnectorDefinition = {\n id: EVOLUTION_CONNECTOR_ID,\n hostPluginId: 'conversations',\n name: 'Evolution API',\n description:\n 'WhatsApp pelo número da própria casa: parea com um QR no celular e manda texto livre, sem template e sem janela de 24h.',\n icon: 'MessageCircle',\n // The channel's mark: the store sees \"WhatsApp\", which is what it connects.\n logoUrl: 'https://assets.fayz.ai/connectors/whatsapp.png',\n category: 'messaging',\n authKind: 'api-key',\n planes: ['request', 'sync'],\n direction: 'outbound',\n docsUrl: 'https://doc.evolution-api.com',\n // A message that does not go out must never take the order with it: past\n // this budget the send gives up and the order carries on.\n latencyBudgetMs: 3000,\n onFailure: 'degrade',\n permissions: [\n {\n kind: 'data',\n resource: 'conversation',\n actions: ['read', 'write'],\n reason: 'Abrir a conversa do cliente no WhatsApp e mantê-la em dia.',\n },\n {\n kind: 'data',\n resource: 'message',\n actions: ['read', 'write'],\n reason: 'Guardar cada mensagem enviada e recebida, com fotos, áudios e documentos.',\n },\n ],\n // The URL, the key and the instance are typed in the provider card below,\n // which already saves them where the sender reads them.\n fields: [],\n invokedAt: [\n {\n key: 'messaging.send',\n label: 'Uma automação ou um pedido manda mensagem e ela sai pelo WhatsApp da casa',\n touches: ['conversation', 'message'],\n },\n {\n key: 'conversations.inbound',\n label: 'O cliente responde, e a resposta entra na caixa de entrada',\n plane: 'sync',\n trigger: 'webhook',\n touches: ['conversation', 'message'],\n },\n ],\n howItSyncs: [\n 'As mensagens saem pelo número da própria casa, pareado lendo um QR com o WhatsApp do celular (Aparelhos conectados).',\n 'Manda texto livre para qualquer cliente, sem template aprovado e sem a janela de 24h do WhatsApp oficial.',\n 'É o WhatsApp Web por baixo: o número pode ser banido sem aviso e a sessão pode cair. Use um número já ativo, e pareie de novo se cair.',\n ],\n getStatus: evolutionStatus,\n disconnectNote:\n 'Para desconectar, desative o provedor ou desconecte o aparelho no WhatsApp do celular. As conversas que já existem continuam aqui.',\n ExtraPanel: EvolutionPanel,\n}\n","import * as React from 'react'\nimport { getSupabaseClientOptional, useActiveTenantId } from '@fayz-ai/core'\nimport { notifySystem, playChime, requestNotificationPermission, useNavContribution } from '@fayz-ai/admin'\n\nimport { T } from '../data/tables'\nimport { assinarChegada } from '../lib/campainha'\nimport { isWaitingOnUs } from '../types'\n\n// ---------------------------------------------------------------------------\n// THE INBOX WATCHER: no button, no panel. It counts what is waiting on us and\n// writes the count on the rail's «Conversas» line, chimes, and raises the\n// system notification.\n//\n// Conversas is a destination with its own screen again — a rail line, like\n// before 09-28. The header icon and the right-column inbox (10-15) squeezed\n// the thread into a sliver and lost what the full screen does (the contact\n// panel, media at full size, the page actions). The line on the rail is where\n// the count shows.\n//\n// ── why it is mounted as a header control ──────────────────────────────\n//\n// Header controls render OUTSIDE the route switch. A hook inside the\n// Conversas screen only lives while the screen lives: leaving the inbox would\n// kill the alert — exactly when it matters, because the operator is on the\n// funnel, on a lead, on the financial screens. It renders nothing.\n//\n// ── the sound is generated, not a file ─────────────────────────────────\n//\n// An .mp3 in the package means a binary in the bundle and a silent 404 the\n// day the asset path changes. Two WebAudio oscillators make a half-second\n// note. It plays only after the person's FIRST GESTURE on the page: no\n// browser allows audio before that. Before the gesture, the badge alone.\n//\n// ── and why it counts on its own instead of reading the store ──────────\n//\n// The inbox store lives inside the plugin's context, which wraps its SCREENS,\n// not the header. The watcher is outside that context on purpose (that keeps\n// it alive across navigation), so it does its own read: cheap, because it\n// asks only for the three columns that decide the count.\n// ---------------------------------------------------------------------------\n\n// The chime, the permission prompt and the system notification live in\n// @fayz-ai/admin (lib/attention.ts) since the shell's bell needs the same three;\n// the rules that shaped them were written here first.\nconst tocar = playChime\nconst pedirPermissao = requestNotificationPermission\nconst avisarNoSistema = (titulo: string, corpo: string, tag: string) => notifySystem(titulo, corpo, tag)\n\nconst RAIL_ID = 'conversations'\n\nexport function InboxWatcher({ label, route = '/conversations', section = 'main', position = 1 }: {\n /** The inbox's name: the rail line's label and the system notification's title. */\n label: string\n route?: string\n /** Where the rail line sits — the same values the plugin declares it with. */\n section?: 'main' | 'secondary' | 'settings'\n position?: number\n}) {\n const tenantId = useActiveTenantId()\n const [naoLidas, setNaoLidas] = React.useState(0)\n const podeTocar = React.useRef(false)\n\n // O primeiro gesto libera o áudio. `once` em três eventos porque o gesto que\n // conta varia: rato no desktop, toque no telefone, tecla em quem navega pelo\n // teclado.\n React.useEffect(() => {\n const liberar = () => {\n podeTocar.current = true\n // O mesmo gesto que libera o som serve para pedir a permissão: é o único\n // instante em que o navegador aceita o pedido, e gastar dois gestos para\n // duas permissões seria gastar o segundo à toa.\n void pedirPermissao()\n }\n for (const ev of ['pointerdown', 'keydown', 'touchstart']) {\n window.addEventListener(ev, liberar, { once: true, passive: true })\n }\n return () => { for (const ev of ['pointerdown', 'keydown', 'touchstart']) window.removeEventListener(ev, liberar) }\n }, [])\n\n const contar = React.useCallback(async () => {\n const supabase = getSupabaseClientOptional() as any\n if (!supabase) return\n // Só o que decide `isWaitingOnUs`: estado, direção da última e a conta.\n // Pedir a conversa inteira aqui seria carregar a caixa toda a cada\n // mensagem, em toda tela do app.\n const { data } = await supabase\n .from(T.conversations)\n .select('id, status, last_message_direction, unread_count')\n .eq('status', 'open')\n if (!data) return\n const n = (data as any[]).filter((r) => isWaitingOnUs({\n status: r.status,\n lastMessageDirection: r.last_message_direction ?? undefined,\n unreadCount: r.unread_count ?? 0,\n } as any)).length\n setNaoLidas(n)\n }, [])\n\n React.useEffect(() => { void contar() }, [contar])\n\n // UMA assinatura, partilhada com a caixa aberta.\n //\n // Dois canais com o mesmo tópico no mesmo cliente não recebem os dois: um\n // vence. Em produção quem venceu foi a tela — a mensagem aparecia sozinha e\n // a notificação do sistema não saía, sem erro nenhum. Cada um testado em\n // separado passava; juntos, um emudecia.\n React.useEffect(() => {\n if (!tenantId) return\n return assinarChegada(tenantId, ({ conversationId }) => {\n void contar()\n if (podeTocar.current) tocar()\n void (async () => {\n const supabase = getSupabaseClientOptional() as any\n let titulo = label\n let corpo = ''\n if (conversationId && supabase) {\n // Leitura normal: RLS aplicada, cabeçalho da conta presente. A\n // campainha traz só o id justamente para o conteúdo vir por aqui.\n const { data } = await supabase\n .from(T.conversations)\n .select('contact_name, last_message_preview')\n .eq('id', conversationId)\n .maybeSingle()\n titulo = (data as any)?.contact_name || label\n corpo = String((data as any)?.last_message_preview || '').replace(/\\s+/g, ' ').slice(0, 140)\n }\n avisarNoSistema(titulo, corpo, String(conversationId ?? 'inbox'))\n })()\n })\n }, [contar, tenantId, label])\n\n // The count goes on the rail line. The plugin declares the line itself; this\n // contribution only adds the badge, merged into it by route.\n useNavContribution('conversations:unread', naoLidas > 0\n ? [{ id: 'conversations', label, route, badge: naoLidas, badgeTone: 'destructive', section, position }]\n : [])\n\n return null\n}\n","import type { Channel } from '../types'\n\n// Solid brand hex per channel — mirrors CHANNEL_ACCENT in ../channel.ts but\n// React-free so the data providers can stamp a sensible avatar accent on new\n// conversations without importing the icon layer.\nexport const CHANNEL_ACCENT_HEX: Record<Channel, string> = {\n whatsapp: '#22c55e',\n sms: '#6366f1',\n instagram: '#ec4899',\n email: '#0ea5e9',\n webchat: '#f59e0b',\n}\n","import type { ConversationsProvider } from './types'\nimport { CHANNEL_ACCENT_HEX } from './accents'\nimport type {\n Conversation,\n Message,\n ListConversationsQuery,\n SendMessageInput,\n CreateConversationInput,\n ConversationStatus,\n} from '../types'\n\n// Deterministic relative timestamps (no Date.now at module init for stable seeds).\nfunction minutesAgo(base: number, mins: number): string {\n return new Date(base - mins * 60_000).toISOString()\n}\n\nfunction seed(): { conversations: Conversation[]; messages: Message[] } {\n const base = new Date('2026-06-16T14:00:00Z').getTime()\n\n const conversations: Conversation[] = [\n {\n id: 'c1', contactName: 'Marina Alves', contactHandle: '+55 11 99876-1020', channel: 'whatsapp',\n lastMessagePreview: 'Perfect, can we book for Friday at 3pm?', lastMessageAt: minutesAgo(base, 4),\n lastMessageDirection: 'inbound',\n unreadCount: 2, status: 'open', assignedTo: 'You', accent: '#22c55e', tags: ['Hot lead'],\n location: 'São Paulo, BR', note: 'Referred by Instagram ad — interested in full color + cut.',\n },\n {\n id: 'c2', contactName: 'Jordan Pierce', contactHandle: '+1 (415) 555-0142', channel: 'sms',\n lastMessagePreview: 'Got it — sending the deposit now.', lastMessageAt: minutesAgo(base, 22),\n lastMessageDirection: 'inbound',\n unreadCount: 0, status: 'open', assignedTo: 'You', accent: '#6366f1', tags: ['Customer'],\n location: 'San Francisco, US',\n },\n {\n id: 'c3', contactName: '@thehairloft', contactHandle: 'thehairloft', channel: 'instagram',\n lastMessagePreview: 'Do you offer balayage on weekends?', lastMessageAt: minutesAgo(base, 51),\n lastMessageDirection: 'inbound',\n unreadCount: 1, status: 'open', accent: '#ec4899', tags: ['New'],\n },\n {\n id: 'c4', contactName: 'David Whitman', contactHandle: 'david@whitman.co', channel: 'email',\n lastMessagePreview: 'Re: Proposal — looks great, one question on pricing…', lastMessageAt: minutesAgo(base, 95),\n // Read, never answered — zero unread and a customer still waiting. The\n // exact case `unreadCount` alone gets wrong.\n lastMessageDirection: 'inbound',\n unreadCount: 0, status: 'open', assignedTo: 'Sofia', accent: '#0ea5e9', tags: ['Proposal'],\n location: 'Austin, US', note: 'Evaluating the retainer tier. Decision expected this week.',\n },\n {\n id: 'c5', contactName: 'Website visitor', contactHandle: 'live chat · acme.com', channel: 'webchat',\n lastMessagePreview: 'Is anyone available to chat?', lastMessageAt: minutesAgo(base, 140),\n lastMessageDirection: 'inbound',\n unreadCount: 0, status: 'snoozed', accent: '#f59e0b', tags: [],\n },\n {\n id: 'c6', contactName: 'Priya Nair', contactHandle: '+44 7700 900123', channel: 'whatsapp',\n lastMessagePreview: 'Thank you! See you next week 🙌', lastMessageAt: minutesAgo(base, 1440),\n lastMessageDirection: 'outbound',\n unreadCount: 0, status: 'closed', assignedTo: 'You', accent: '#14b8a6', tags: ['Customer'],\n location: 'London, UK',\n },\n ]\n\n const messages: Message[] = [\n msg('m1', 'c1', 'whatsapp', 'inbound', 'Hi! I saw your ad — do you have availability this week?', 'Marina Alves', minutesAgo(base, 18)),\n msg('m2', 'c1', 'whatsapp', 'outbound', 'Hi Marina! Yes, we do. What service are you interested in?', 'You', minutesAgo(base, 15)),\n msg('m3', 'c1', 'whatsapp', 'inbound', 'A full color + cut.', 'Marina Alves', minutesAgo(base, 9)),\n msg('m4', 'c1', 'whatsapp', 'inbound', 'Perfect, can we book for Friday at 3pm?', 'Marina Alves', minutesAgo(base, 4)),\n\n msg('m5', 'c2', 'sms', 'outbound', 'Your appointment is confirmed for tomorrow at 10am.', 'You', minutesAgo(base, 40)),\n msg('m6', 'c2', 'sms', 'inbound', 'Got it — sending the deposit now.', 'Jordan Pierce', minutesAgo(base, 22)),\n\n msg('m7', 'c3', 'instagram', 'inbound', 'Do you offer balayage on weekends?', '@thehairloft', minutesAgo(base, 51)),\n\n msg('m8', 'c4', 'email', 'inbound', 'Re: Proposal — looks great, one question on pricing for the retainer tier.', 'David Whitman', minutesAgo(base, 95)),\n msg('m9', 'c4', 'email', 'outbound', 'Happy to walk you through it — are you free for a quick call tomorrow?', 'Sofia', minutesAgo(base, 80)),\n\n msg('m10', 'c5', 'webchat', 'inbound', 'Is anyone available to chat?', 'Website visitor', minutesAgo(base, 140)),\n\n msg('m11', 'c6', 'whatsapp', 'outbound', 'You are all set for next Tuesday. Anything else?', 'You', minutesAgo(base, 1500)),\n msg('m12', 'c6', 'whatsapp', 'inbound', 'Thank you! See you next week 🙌', 'Priya Nair', minutesAgo(base, 1440)),\n ]\n\n return { conversations, messages }\n}\n\nfunction msg(\n id: string, conversationId: string, channel: Message['channel'],\n direction: Message['direction'], body: string, author: string, at: string,\n): Message {\n return { id, conversationId, channel, direction, body, author, at }\n}\n\nexport interface MockConversationsConfig {\n /** Tenant id (value or getter) used to namespace the localStorage snapshot. */\n tenantId?: string | (() => string | undefined)\n /** Display name stamped as the author of outbound messages. */\n selfAuthor?: string\n}\n\ninterface Snapshot {\n conversations: Conversation[]\n messages: Message[]\n counter: number\n}\n\n// ---------------------------------------------------------------------------\n// In-memory mock inbox with best-effort localStorage persistence, so a browser\n// reload keeps whatever the demo created/sent within the session. The store is\n// namespaced per tenant; SSR / no-window environments degrade to pure memory.\n// ---------------------------------------------------------------------------\nexport function createMockConversationsProvider(\n config?: MockConversationsConfig,\n): ConversationsProvider {\n const selfAuthor = config?.selfAuthor ?? 'You'\n\n function resolveTenant(): string {\n const raw = typeof config?.tenantId === 'function' ? config.tenantId() : config?.tenantId\n return raw || 'default'\n }\n\n const storageKey = () => `saas:mock:conversations:${resolveTenant()}`\n\n function hasStorage(): boolean {\n try {\n return typeof window !== 'undefined' && !!window.localStorage\n } catch {\n return false\n }\n }\n\n function load(): Snapshot {\n if (hasStorage()) {\n try {\n const raw = window.localStorage.getItem(storageKey())\n if (raw) {\n const parsed = JSON.parse(raw) as Snapshot\n if (Array.isArray(parsed.conversations) && Array.isArray(parsed.messages)) {\n return {\n conversations: parsed.conversations,\n messages: parsed.messages,\n counter: parsed.counter ?? 100,\n }\n }\n }\n } catch {\n // Corrupt snapshot — fall through to a fresh seed.\n }\n }\n const seeded = seed()\n return { conversations: seeded.conversations, messages: seeded.messages, counter: 100 }\n }\n\n const state = load()\n\n function persist(): void {\n if (!hasStorage()) return\n try {\n window.localStorage.setItem(\n storageKey(),\n JSON.stringify({\n conversations: state.conversations,\n messages: state.messages,\n counter: state.counter,\n } satisfies Snapshot),\n )\n } catch {\n // Quota / privacy mode — keep working in memory only.\n }\n }\n\n // Persist the initial seed so a first reload is already stable.\n persist()\n\n return {\n async listConversations(query?: ListConversationsQuery): Promise<Conversation[]> {\n let list = [...state.conversations]\n if (query?.channel && query.channel !== 'all') list = list.filter((c) => c.channel === query.channel)\n if (query?.status && query.status !== 'all') list = list.filter((c) => c.status === query.status)\n if (query?.search) {\n const q = query.search.toLowerCase()\n list = list.filter(\n (c) => c.contactName.toLowerCase().includes(q) || c.lastMessagePreview.toLowerCase().includes(q),\n )\n }\n return list.sort((a, b) => b.lastMessageAt.localeCompare(a.lastMessageAt))\n },\n\n async getMessages(conversationId: string): Promise<Message[]> {\n return state.messages\n .filter((m) => m.conversationId === conversationId)\n .sort((a, b) => a.at.localeCompare(b.at))\n },\n\n async createConversation(input: CreateConversationInput): Promise<Conversation> {\n const now = new Date().toISOString()\n const firstMessage = input.firstMessage?.trim()\n const id = `c${++state.counter}`\n const conversation: Conversation = {\n id,\n contactName: input.contactName.trim(),\n contactPersonId: input.contactPersonId,\n contactHandle: input.contactHandle?.trim() ?? '',\n channel: input.channel,\n lastMessagePreview: firstMessage ?? '',\n lastMessageAt: now,\n // A thread the house opened is not waiting on the house. Left undefined\n // when there is no first message: nobody has spoken, so there is no\n // last speaker to name, and `isWaitingOnUs` falls back to unread (0).\n lastMessageDirection: firstMessage ? 'outbound' : undefined,\n unreadCount: 0,\n status: 'open',\n assignedTo: selfAuthor,\n accent: CHANNEL_ACCENT_HEX[input.channel],\n tags: [],\n note: input.note?.trim() || undefined,\n }\n state.conversations.unshift(conversation)\n if (firstMessage) {\n state.messages.push({\n id: `m${++state.counter}`,\n conversationId: id,\n channel: input.channel,\n direction: 'outbound',\n body: firstMessage,\n author: selfAuthor,\n at: now,\n })\n }\n persist()\n return conversation\n },\n\n async sendMessage(input: SendMessageInput): Promise<Message> {\n const conv = state.conversations.find((c) => c.id === input.conversationId)\n const created: Message = {\n id: `m${++state.counter}`,\n conversationId: input.conversationId,\n channel: conv?.channel ?? 'sms',\n direction: 'outbound',\n body: input.body,\n author: selfAuthor,\n at: new Date().toISOString(),\n }\n state.messages.push(created)\n if (conv) {\n conv.lastMessagePreview = input.body\n conv.lastMessageAt = created.at\n conv.lastMessageDirection = 'outbound'\n conv.unreadCount = 0\n if (conv.status === 'closed') conv.status = 'open'\n }\n persist()\n return created\n },\n\n async markRead(conversationId: string): Promise<void> {\n const conv = state.conversations.find((c) => c.id === conversationId)\n if (conv && conv.unreadCount !== 0) {\n conv.unreadCount = 0\n persist()\n }\n },\n\n async setStatus(conversationId: string, status: ConversationStatus): Promise<Conversation> {\n const conv = state.conversations.find((c) => c.id === conversationId)\n if (!conv) throw new Error('Conversation not found')\n conv.status = status\n persist()\n return conv\n },\n }\n}\n","import { getSupabaseClientOptional } from '@fayz-ai/core'\nimport type { ConversationsProvider } from './types'\nimport { T } from './tables'\nimport { CHANNEL_ACCENT_HEX } from './accents'\nimport type {\n Conversation,\n Message,\n ListConversationsQuery,\n SendMessageInput,\n CreateConversationInput,\n ConversationStatus,\n MessageDirection,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// Supabase-backed conversations provider — reads/writes the project's\n// `conversations` + `conversation_messages` tables (tenant-scoped via RLS +\n// an explicit tenant filter from the active-org context). Mirrors the inline\n// client-casting style of @fayz-ai/core's createSupabaseProvider; the global\n// client is `unknown`-typed so each call narrows the shape it needs.\n//\n// Real channel connectors (Twilio, WhatsApp Cloud, Meta, IMAP) deliver inbound\n// rows into these tables out-of-band; this provider is the read/compose surface.\n// ---------------------------------------------------------------------------\n\nexport interface SupabaseConversationsConfig {\n /** Supabase client; defaults to the global one registered by createFayzApp. */\n supabaseClient?: unknown\n /** Active tenant id (value or getter) used to scope reads and stamp writes. */\n tenantId?: string | (() => string | undefined)\n /** Display name stamped as the author of outbound messages. */\n selfAuthor?: string\n}\n\ntype Row = Record<string, unknown>\n\nfunction mapConversation(r: Row): Conversation {\n return {\n id: String(r.id),\n contactName: (r.contact_name as string) ?? '',\n contactPersonId: (r.contact_person_id as string | null) ?? undefined,\n contactHandle: (r.contact_handle as string) ?? '',\n channel: (r.channel as Conversation['channel']) ?? 'sms',\n lastMessagePreview: (r.last_message_preview as string) ?? '',\n lastMessageAt: (r.last_message_at as string) ?? '',\n // Kept current by the trigger in migration 001, never written from here:\n // the column has one writer on purpose (last_message_preview/at have five,\n // which is the mistake this one was not going to repeat).\n lastMessageDirection: (r.last_message_direction as MessageDirection | null) ?? undefined,\n unreadCount: Number(r.unread_count ?? 0),\n acknowledgedAt: (r.acknowledged_at as string | null) ?? null,\n status: (r.status as ConversationStatus) ?? 'open',\n assignedTo: (r.assigned_to as string | null) ?? undefined,\n // Presentes só quando a leitura veio da view. Na escrita (que volta da\n // tabela) ficam nulos, e a lista recarrega logo a seguir.\n leadOwnerId: (r.lead_owner_id as string | null) ?? undefined,\n leadOwnerName: (r.lead_owner_name as string | null) ?? undefined,\n accent: (r.accent as string) ?? '#6366f1',\n tags: (r.tags as string[] | null) ?? [],\n location: (r.location as string | null) ?? undefined,\n note: (r.note as string | null) ?? undefined,\n }\n}\n\nfunction mapMessage(r: Row): Message {\n return {\n id: String(r.id),\n conversationId: String(r.conversation_id),\n channel: (r.channel as Message['channel']) ?? 'sms',\n direction: (r.direction as Message['direction']) ?? 'inbound',\n body: (r.body as string) ?? '',\n at: (r.at as string) ?? '',\n author: (r.author as string) ?? '',\n deliveryStatus: (r.delivery_status as string) ?? null,\n providerMessageId: (r.provider_message_id as string) ?? null,\n // NULL stays null rather than defaulting to 'text'. A row written before\n // migration 012 genuinely does not know what it was, and the rows that most\n // need saying so are the empty ones that a 'text' default would call fine.\n messageType: (r.message_type as Message['messageType']) ?? null,\n payload: (r.payload as Message['payload']) ?? null,\n mediaPath: (r.media_path as string) ?? null,\n }\n}\n\nexport function createSupabaseConversationsProvider(\n config?: SupabaseConversationsConfig,\n): ConversationsProvider {\n /** O que o provedor chama de status, no vocabulário que a nossa coluna aceita.\n * Um valor desconhecido vira `sent`: a mensagem saiu, e inventar um estado\n * que o CHECK recusa transforma um envio bem-sucedido num erro. */\nconst DELIVERY = new Set(['queued','sent','delivered','read','failed','expired','delivery_timeout','cancelled','opted_out'])\nfunction mapDeliveryStatus(raw: unknown): string {\n const v = String(raw ?? '').toLowerCase()\n if (v === 'accepted' || v === 'received') return 'sent'\n return DELIVERY.has(v) ? v : 'sent'\n}\n\nconst selfAuthor = config?.selfAuthor ?? 'You'\n\n function resolveTenantId(): string | undefined {\n if (!config?.tenantId) return undefined\n return typeof config.tenantId === 'function' ? config.tenantId() : config.tenantId\n }\n\n function client(): { from: (t: string) => Row } {\n const supabase = (config?.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 return supabase\n }\n\n return {\n async listConversations(query?: ListConversationsQuery): Promise<Conversation[]> {\n // A VIEW, não a tabela: ela traz o dono do lead junto, e sem isso a\n // caixa teria de resolver o de-para por conversa no cliente.\n let q = (client().from(T.conversationsView) as { select: (s: string) => Row }).select('*')\n\n const tenantId = resolveTenantId()\n if (tenantId) q = (q as { eq: (c: string, v: string) => Row }).eq('tenant_id', tenantId)\n if (query?.channel && query.channel !== 'all') {\n q = (q as { eq: (c: string, v: string) => Row }).eq('channel', query.channel)\n }\n if (query?.status && query.status !== 'all') {\n q = (q as { eq: (c: string, v: string) => Row }).eq('status', query.status)\n }\n if (query?.leadOwnerId === 'none') {\n q = (q as { is: (c: string, v: null) => Row }).is('lead_owner_id', null)\n } else if (query?.leadOwnerId) {\n q = (q as { eq: (c: string, v: string) => Row }).eq('lead_owner_id', query.leadOwnerId)\n }\n if (query?.search) {\n const term = `%${query.search}%`\n q = (q as { or: (c: string) => Row }).or(\n `contact_name.ilike.${term},last_message_preview.ilike.${term}`,\n )\n }\n q = (q as { order: (c: string, o: unknown) => Row }).order('last_message_at', {\n ascending: false,\n })\n\n const { data, error } = (await q) as { data: Row[] | null; error: unknown }\n if (error) throw error\n return (data ?? []).map(mapConversation)\n },\n\n async getMessages(conversationId: string): Promise<Message[]> {\n const selected = (\n client().from(T.messages) as { select: (s: string) => Row }\n ).select('*')\n const filtered = (selected as { eq: (c: string, v: string) => Row }).eq(\n 'conversation_id',\n conversationId,\n )\n const ordered = (filtered as { order: (c: string, o: unknown) => Row }).order('at', {\n ascending: true,\n })\n const { data, error } = (await ordered) as { data: Row[] | null; error: unknown }\n if (error) throw error\n return (data ?? []).map(mapMessage)\n },\n\n async createConversation(input: CreateConversationInput): Promise<Conversation> {\n const tenantId = resolveTenantId()\n // Insert with a null tenant_id fails the plg_conversations RLS WITH CHECK\n // (tenant_id ∈ user_tenant_ids()) with an opaque Postgres error. When the\n // active tenant hasn't resolved yet (bootstrap race), fail fast with an\n // actionable message the compose modal can surface via toast.\n if (!tenantId) {\n throw new Error('[plugin-conversations] Active tenant not resolved — cannot create conversation. Try again in a moment.')\n }\n const now = new Date().toISOString()\n const firstMessage = input.firstMessage?.trim()\n\n const convRow: Row = {\n contact_name: input.contactName.trim(),\n // Only written when the picker resolved a real person — an app that\n // hasn't run migration 002 yet would reject an unknown column, and\n // omitting it keeps the free-text path working there.\n ...(input.contactPersonId ? { contact_person_id: input.contactPersonId } : {}),\n contact_handle: input.contactHandle?.trim() || null,\n channel: input.channel,\n last_message_preview: firstMessage || null,\n last_message_at: now,\n unread_count: 0,\n status: 'open',\n assigned_to: selfAuthor,\n accent: CHANNEL_ACCENT_HEX[input.channel],\n tags: [],\n note: input.note?.trim() || null,\n }\n if (tenantId) convRow.tenant_id = tenantId\n\n const { data: created, error } = (await (\n (client().from(T.conversations) as { insert: (r: Row) => Row }).insert(convRow) as {\n select: () => { single: () => Promise<{ data: Row | null; error: unknown }> }\n }\n )\n .select()\n .single()) as { data: Row | null; error: unknown }\n if (error) throw error\n if (!created) throw new Error('Conversation not created')\n\n // Seed the thread with the first outbound message when provided.\n if (firstMessage) {\n const msgRow: Row = {\n conversation_id: String(created.id),\n channel: input.channel,\n direction: 'outbound',\n body: firstMessage,\n author: selfAuthor,\n at: now,\n }\n if (tenantId) msgRow.tenant_id = tenantId\n await (client().from(T.messages) as { insert: (r: Row) => Promise<unknown> }).insert(msgRow)\n }\n\n return mapConversation(created)\n },\n\n async sendMessage(input: SendMessageInput): Promise<Message> {\n\n const tenantId = resolveTenantId()\n\n // Resolve the channel from the parent conversation so the message matches.\n const convSelected = (client().from(T.conversations) as { select: (s: string) => Row }).select(\n 'channel, contact_handle',\n )\n const convFiltered = (convSelected as { eq: (c: string, v: string) => Row }).eq(\n 'id',\n input.conversationId,\n )\n const { data: conv } = (await (\n convFiltered as { maybeSingle: () => Promise<{ data: Row | null }> }\n ).maybeSingle()) as { data: Row | null }\n const channel = (conv?.channel as Message['channel']) ?? 'sms'\n\n const at = new Date().toISOString()\n const row: Row = {\n conversation_id: input.conversationId,\n channel,\n direction: 'outbound',\n body: input.body,\n author: selfAuthor,\n at,\n }\n if (tenantId) row.tenant_id = tenantId\n\n const { data: created, error } = (await (\n (client().from(T.messages) as { insert: (r: Row) => Row }).insert(row) as {\n select: () => { single: () => Promise<{ data: Row | null; error: unknown }> }\n }\n )\n .select()\n .single()) as { data: Row | null; error: unknown }\n if (error) throw error\n\n // E AGORA A MENSAGEM SAI DE VERDADE.\n //\n // Até aqui `sendMessage` gravava a linha e terminava. A caixa mostrava a\n // mensagem enviada, o destinatário nunca recebia nada, e não havia erro\n // em lugar nenhum — duas mensagens ficaram meses paradas nesta tabela\n // antes de alguém perguntar por quê.\n //\n // O envio é DEPOIS da gravação, de propósito: se a entrega falhar, a\n // linha continua existindo com a falha registrada. O contrário — mandar\n // e só então gravar — perde a mensagem quando a gravação falha, e aí\n // ninguém sabe o que foi dito.\n //\n // A falha não é silenciosa: ela sobe. Quem chamou decide o que mostrar.\n // O que o envio devolveu, para o objeto RETORNADO carregar. A primeira\n // versão devolvia a linha capturada ANTES do envio: sem id do provedor e\n // sem status. A caixa então desenhava vermelho — \"sem id, não saiu\" — uma\n // mensagem que tinha acabado de ser entregue. O banco estava certo e a\n // tela mentia até o próximo recarregamento.\n let sentId: string | null = null\n let sentStatus: string | null = null\n\n if (channel === 'whatsapp') {\n const handle = String((conv as Row | null)?.contact_handle ?? '')\n try {\n const { data: out, error: sendErr } = await (client() as any).functions.invoke(\n 'conversations-provider',\n { body: { tenantId, action: 'send', to: handle, text: input.body } },\n )\n if (sendErr) {\n const detail = (await sendErr.context?.json?.().catch(() => null)) as { message?: string } | null\n throw new Error(detail?.message ?? sendErr.message)\n }\n if ((out as any)?.error) throw new Error((out as any).message ?? (out as any).error)\n sentId = (out as any)?.providerMessageId ?? null\n // `queued` é uma resposta, não uma falha: o provedor desta casa só é\n // alcançável da máquina dela, e a nuvem deixou a linha para o\n // disparador local. O balão fica cinza com o relógio até ele passar.\n sentStatus = (out as any)?.queued ? 'queued' : mapDeliveryStatus((out as any)?.status)\n if (created?.id) {\n await ((client().from(T.messages) as { update: (r: Row) => Row }).update({\n provider_message_id: sentId,\n // O provedor fala o dialeto dele. A Tyxter devolve `accepted`,\n // que NÃO existe no CHECK desta coluna — o update explodia, caía\n // no catch, e a mensagem era marcada como falha mesmo tendo\n // saído. Foi assim que \"opa\" apareceu verde e contou como erro.\n delivery_status: sentStatus,\n }) as { eq: (c: string, v: string) => Promise<unknown> }).eq('id', String(created.id))\n }\n } catch (err) {\n if (created?.id) {\n await ((client().from(T.messages) as { update: (r: Row) => Row }).update({\n delivery_status: 'failed',\n }) as { eq: (c: string, v: string) => Promise<unknown> }).eq('id', String(created.id))\n }\n throw err\n }\n }\n\n // Roll the parent conversation forward (preview / timestamp / unread / reopen).\n await (\n (client().from(T.conversations) as {\n update: (r: Row) => Row\n }).update({\n last_message_preview: input.body,\n last_message_at: at,\n unread_count: 0,\n status: 'open',\n }) as { eq: (c: string, v: string) => Promise<unknown> }\n ).eq('id', input.conversationId)\n\n return {\n ...mapMessage(created ?? row),\n providerMessageId: sentId,\n deliveryStatus: sentStatus,\n }\n },\n\n async markRead(conversationId: string): Promise<void> {\n const { error } = (await (\n (client().from(T.conversations) as { update: (r: Row) => Row }).update({\n unread_count: 0,\n // O instante é o que tira a bolinha. `unread_count` sozinho não\n // tirava — a fila olha a DIREÇÃO da última mensagem, e ela continua\n // sendo de entrada por mais que alguém leia.\n acknowledged_at: new Date().toISOString(),\n }) as { eq: (c: string, v: string) => Promise<{ error: unknown }> }\n ).eq('id', conversationId)) as { error: unknown }\n if (error) throw error\n },\n\n async setStatus(conversationId: string, status: ConversationStatus): Promise<Conversation> {\n const updated = (client().from(T.conversations) as { update: (r: Row) => Row }).update({\n status,\n })\n const filtered = (updated as { eq: (c: string, v: string) => Row }).eq('id', conversationId)\n const selected = (filtered as { select: () => Row }).select()\n const { data, error } = (await (\n selected as { single: () => Promise<{ data: Row | null; error: unknown }> }\n ).single()) as { data: Row | null; error: unknown }\n if (error) throw error\n if (!data) throw new Error('Conversation not found')\n return mapConversation(data)\n },\n }\n}\n","import { createStore, type StoreApi } from 'zustand/vanilla'\nimport type { ConversationsProvider } from './data/types'\nimport type {\n Conversation,\n Message,\n Channel,\n ConversationStatus,\n CreateConversationInput,\n} from './types'\n\n/** Quem, por onde, e como chamá-lo. Vem de outro módulo — hoje a ficha do lead\n * no CRM — que sabe a pessoa e não sabe nada sobre conversas. */\nexport interface OpenForPersonInput {\n /** `public.people` id. É por ele que a conversa é reconhecida; o telefone é\n * o desempate para threads antigas, criadas antes de haver vínculo. */\n personId?: string\n name: string\n handle: string\n channel: Channel\n}\n\n/** Só os dígitos. `+55 11 99999-0000` e `5511999990000` são o mesmo telefone, e\n * comparar como texto cru abriria uma segunda thread para a mesma pessoa. */\nfunction handleKey(h: string | undefined | null): string {\n const v = (h ?? '').trim()\n if (!v) return ''\n return /[@a-z]/i.test(v) ? v.toLowerCase() : v.replace(/\\D/g, '')\n}\n\nexport interface ConversationsUIState {\n conversations: Conversation[]\n messages: Message[]\n selectedId: string | null\n refreshMessages: () => Promise<void>\n channelFilter: Channel | 'all'\n /** Recorte por DONO DO LEAD. `'none'` é a fila sem dono. */\n leadOwnerFilter?: string | 'none'\n search: string\n loading: boolean\n sending: boolean\n\n /** `autoSelect: false` lists without opening (and marking read) the first\n * conversation — the compact floating inbox starts on the list. */\n load(opts?: { autoSelect?: boolean }): Promise<void>\n select(id: string): Promise<void>\n /** Dar por vista SEM abrir — o \"ok, obrigado\" que não pede resposta. */\n markRead(id: string): Promise<void>\n deselect(): void\n setChannelFilter(channel: Channel | 'all'): Promise<void>\n setLeadOwnerFilter(ownerId?: string | 'none'): Promise<void>\n setSearch(search: string): Promise<void>\n create(input: CreateConversationInput): Promise<Conversation>\n /** Abrir a conversa DESTA pessoa neste canal, criando-a se ainda não houver. */\n openForPerson(input: OpenForPersonInput): Promise<Conversation>\n send(body: string): Promise<void>\n setStatus(status: ConversationStatus): Promise<void>\n}\n\nexport function createConversationsStore(\n provider: ConversationsProvider,\n): StoreApi<ConversationsUIState> {\n return createStore<ConversationsUIState>((set, get) => ({\n conversations: [],\n messages: [],\n selectedId: null,\n channelFilter: 'all',\n leadOwnerFilter: undefined,\n search: '',\n loading: false,\n sending: false,\n\n async load(opts) {\n set({ loading: true })\n const conversations = await provider.listConversations({\n channel: get().channelFilter,\n leadOwnerId: get().leadOwnerFilter,\n search: get().search || undefined,\n })\n const selectedId = get().selectedId ?? (opts?.autoSelect === false ? null : conversations[0]?.id ?? null)\n set({ conversations, loading: false, selectedId })\n if (selectedId) await get().select(selectedId)\n },\n\n /** Dar por vista sem abrir — o caso do \"ok, obrigado\" que não pede resposta. */\n async markRead(id: string) {\n await provider.markRead(id)\n const agora = new Date().toISOString()\n set((s) => ({\n conversations: s.conversations.map((c) => (\n c.id === id ? { ...c, unreadCount: 0, acknowledgedAt: agora } : c\n )),\n }))\n },\n\n async select(id: string) {\n set({ selectedId: id })\n const messages = await provider.getMessages(id)\n set({ messages })\n await provider.markRead(id)\n // `acknowledgedAt` junto, e não só o contador: é ele que tira a conversa\n // da fila. Sem isto a bolinha continuava acesa depois de abrir e ler.\n const agora = new Date().toISOString()\n set((s) => ({\n conversations: s.conversations.map((c) => (\n c.id === id ? { ...c, unreadCount: 0, acknowledgedAt: agora } : c\n )),\n }))\n },\n\n /** Relê as mensagens da conversa aberta, sem tocar em mais nada.\n *\n * O status de uma mensagem de WhatsApp muda DEPOIS do envio — entregue,\n * lida, às vezes minutos depois — e quem avisa é o webhook, que escreve no\n * banco sem a tela saber. Sem isto a caixa mostra para sempre o status do\n * instante do envio: um tique só, numa mensagem que já foi lida.\n *\n * Não usa `select()` de propósito: aquele marca a conversa como lida e\n * zera o contador, e uma releitura de fundo não é um gesto de ninguém. */\n async refreshMessages() {\n const id = get().selectedId\n if (!id) return\n try {\n const messages = await provider.getMessages(id)\n // Só escreve se mudou algo. `set` a cada dez segundos redesenharia a\n // thread inteira e roubaria a seleção de texto de quem está lendo.\n const before = get().messages\n const same = before.length === messages.length &&\n before.every((m, i) => m.id === messages[i].id && m.deliveryStatus === messages[i].deliveryStatus)\n if (!same) set({ messages })\n } catch { /* a caixa continua com o que tem; a próxima volta tenta de novo */ }\n },\n\n deselect() {\n set({ selectedId: null, messages: [] })\n },\n\n async setLeadOwnerFilter(ownerId) {\n set({ leadOwnerFilter: ownerId })\n await get().load()\n },\n\n async setChannelFilter(channel) {\n set({ channelFilter: channel })\n await get().load()\n },\n\n async setSearch(search) {\n set({ search })\n await get().load()\n },\n\n async create(input) {\n const created = await provider.createConversation(input)\n // The thread EXISTS the moment the insert returns, so resolve on that and\n // show it optimistically. Clear filters that would hide it, prepend it,\n // select it — all local.\n set((s) => ({\n channelFilter: 'all',\n search: '',\n conversations: [created, ...s.conversations.filter((c) => c.id !== created.id)],\n selectedId: created.id,\n }))\n\n // Reconciliation (authoritative list + the thread's messages) runs in the\n // BACKGROUND. It used to be awaited here, which made the caller — the\n // compose modal — hostage to two extra round-trips: on a slow pool the\n // conversation was already in the database while the modal sat open\n // looking broken, inviting a second click and a duplicate thread.\n // Failures are non-fatal: the optimistic row above already renders.\n void (async () => {\n try {\n const conversations = await provider.listConversations({})\n // Read-after-write guard: a refetch that races the insert may not\n // return the new row yet — keep the local one rather than dropping it.\n const merged = conversations.some((c) => c.id === created.id)\n ? conversations\n : [created, ...conversations]\n set({ conversations: merged })\n await get().select(created.id)\n } catch {\n /* optimistic state stands; the next load() reconciles */\n }\n })()\n\n return created\n },\n\n // Chegar aqui vindo de fora — da ficha de um lead, por exemplo — não pode\n // criar uma segunda thread com alguém com quem a casa já conversa. Procura\n // primeiro pela PESSOA, e só então pelo telefone: o vínculo é a verdade, e\n // o handle é o que resgata threads criadas antes de o vínculo existir.\n async openForPerson({ personId, name, handle, channel }) {\n // Uma caixa ainda não carregada não tem como saber que a thread existe.\n if (get().conversations.length === 0 && !get().loading) {\n try { await get().load() } catch { /* segue para a criação */ }\n }\n const key = handleKey(handle)\n const existing = get().conversations.find((c) =>\n c.channel === channel &&\n ((personId && c.contactPersonId === personId) ||\n (key !== '' && handleKey(c.contactHandle) === key)))\n\n if (existing) {\n // Limpa o que esconderia a thread: chegar por link e cair numa lista\n // filtrada é indistinguível de a conversa não existir.\n set({ channelFilter: 'all', search: '' })\n await get().select(existing.id)\n return existing\n }\n\n return get().create({\n contactName: name,\n contactPersonId: personId,\n contactHandle: handle,\n channel,\n })\n },\n\n async send(body: string) {\n const id = get().selectedId\n if (!id || !body.trim()) return\n set({ sending: true })\n const created = await provider.sendMessage({ conversationId: id, body: body.trim() })\n set((s) => ({\n sending: false,\n messages: [...s.messages, created],\n conversations: s.conversations.map((c) =>\n // `lastMessageDirection` acompanha a prévia, senão a fila mente. O\n // gatilho da migration 001 carimba a coluna no banco, mas a lista só\n // volta a ler no próximo `load()` — e até lá a thread que ACABOU de\n // ser respondida continua em \"esperando nós\", que é exatamente a\n // pergunta que essa coluna existe para responder.\n //\n // Antes da 001 isto não aparecia: a coluna vinha sempre indefinida e\n // `isWaitingOnUs` caía no `unreadCount`. A migration não criou o\n // defeito, tornou-o visível.\n c.id === id\n ? { ...c, lastMessagePreview: created.body, lastMessageAt: created.at, lastMessageDirection: 'outbound' as const }\n : c,\n ),\n }))\n },\n\n async setStatus(status) {\n const id = get().selectedId\n if (!id) return\n const updated = await provider.setStatus(id, status)\n set((s) => ({\n conversations: s.conversations.map((c) => (c.id === id ? updated : c)),\n }))\n },\n }))\n}\n","export const en: Record<string, string> = {\n \"conversations.markRead\": \"Mark as read\",\n 'conversations.title': 'Conversations',\n 'conversations.subtitle': 'Unified inbox across every channel',\n\n // Conversation list\n 'conversations.list.search': 'Search conversations',\n 'conversations.list.loading': 'Loading…',\n 'conversations.list.empty': 'No conversations',\n 'conversations.filter.notConnected': 'Account not connected yet',\n 'conversations.list.new': 'New conversation',\n\n // Channel filters\n 'conversations.filter.all': 'All',\n 'conversations.filter.whatsapp': 'WhatsApp',\n 'conversations.filter.sms': 'SMS',\n 'conversations.filter.instagram': 'Instagram',\n 'conversations.filter.email': 'Email',\n 'conversations.filter.webchat': 'Web',\n\n // Status labels\n 'conversations.status.open': 'Open',\n 'conversations.status.snoozed': 'Snoozed',\n 'conversations.status.closed': 'Closed',\n\n // Empty state\n 'conversations.empty.select': 'Select a conversation to start chatting',\n\n // Thread\n 'conversations.thread.back': 'Back to conversations',\n 'conversations.thread.snooze': 'Snooze',\n 'conversations.thread.close': 'Close',\n 'conversations.thread.details': 'Toggle contact details',\n 'conversations.thread.empty': 'No messages yet',\n 'conversations.thread.reply': 'Reply via {{channel}}…',\n 'conversations.thread.send': 'Send',\n\n // Contact panel\n 'conversations.contact.details': 'Details',\n 'conversations.contact.closeDetails': 'Close details',\n 'conversations.contact.channel': 'Channel',\n 'conversations.contact.status': 'Status',\n 'conversations.filter.anyOwner': 'Any owner',\n 'conversations.filter.noOwner': 'No owner',\n 'conversations.contact.leadOwner': 'Lead owner',\n 'conversations.contact.assignedTo': 'Assigned to',\n 'conversations.contact.location': 'Location',\n 'conversations.contact.tags': 'Tags',\n 'conversations.contact.note': 'Note',\n 'conversations.contact.linkedRecords': 'Linked records',\n 'conversations.contact.noLinkedRecords': 'No linked records yet.',\n\n // New-conversation modal\n 'conversations.new.title': 'New conversation',\n 'conversations.new.channel': 'Channel',\n 'conversations.new.contactName': 'Contact name',\n 'conversations.new.contactNamePlaceholder': 'e.g. Jane Doe',\n 'conversations.new.handle': 'Phone / handle / email',\n 'conversations.new.handlePlaceholder': '+1 555 000 0000',\n // The handle field only surfaces when the picked contact has nothing usable\n // for the active channel — otherwise it is derived and shown on the chip.\n 'conversations.new.addHandle': 'Add {label}',\n 'conversations.new.handleLabel.phone': 'phone',\n 'conversations.new.handleLabel.email': 'email',\n 'conversations.new.handleLabel.instagram': 'Instagram handle',\n 'conversations.new.handleLabel.webchat': 'web chat id',\n 'conversations.new.firstMessage': 'First message',\n 'conversations.new.firstMessagePlaceholder': 'Write the first message (optional)…',\n 'conversations.new.cancel': 'Cancel',\n 'conversations.new.create': 'Start conversation',\n 'conversations.new.creating': 'Starting…',\n 'conversations.new.createFailed': 'Could not create the conversation',\n\n // Dashboard — the queue of people waiting on a reply\n 'conversations.dashboard.waiting': 'Waiting on you',\n 'conversations.dashboard.waitingOldest': 'Oldest waiting {{time}}',\n 'conversations.dashboard.waitingNone': 'Nobody waiting',\n 'conversations.dashboard.openThreads': 'Open conversations',\n 'conversations.dashboard.openThreadsSub': '{{count}} waiting on a reply',\n 'conversations.dashboard.needsYou': 'Needs you',\n 'conversations.dashboard.needsYouEmpty': 'Nobody waiting. Inbox is clear.',\n 'conversations.dashboard.who': 'Who',\n 'conversations.dashboard.waited': 'Waiting',\n 'conversations.waited.minutes': '{{count}} min',\n 'conversations.waited.hours': '{{count}} h',\n 'conversations.waited.days': '{{count}} d',\n\n // Inbox settings\n 'conversations.settings.title': 'Conversations',\n 'conversations.settings.channels': 'Your numbers',\n 'conversations.settings.channelsHelp': 'Where messages come in and go out. Connect and manage channels in the Integrations tab.',\n 'conversations.settings.channelsEmpty': 'No channel connected yet — until then the inbox stays empty. Connect WhatsApp in the Integrations tab.',\n 'conversations.settings.channelsUnavailable': 'Could not load your channels right now.',\n 'conversations.settings.channelDedicated': 'Your own number',\n 'conversations.settings.channelShared': 'Platform number',\n 'conversations.settings.status.active': 'Active',\n 'conversations.settings.status.requested': 'Requested',\n 'conversations.settings.status.provisioning': 'Provisioning',\n 'conversations.settings.status.provisioned': 'Provisioned',\n 'conversations.settings.status.verifying': 'Verifying',\n 'conversations.settings.status.failed': 'Failed',\n 'conversations.settings.status.released': 'Released',\n 'conversations.settings.status.disconnected': 'Disconnected',\n}\n","export const ptBR: Record<string, string> = {\n \"conversations.markRead\": \"Marcar como lida\",\n 'conversations.title': 'Conversas',\n 'conversations.subtitle': 'Caixa de entrada unificada de todos os canais',\n\n // Lista de conversas\n 'conversations.list.search': 'Buscar conversas',\n 'conversations.list.loading': 'Carregando…',\n 'conversations.list.empty': 'Nenhuma conversa',\n 'conversations.filter.notConnected': 'Conta ainda não conectada',\n 'conversations.list.new': 'Nova conversa',\n\n // Filtros de canal\n 'conversations.filter.all': 'Todas',\n 'conversations.filter.whatsapp': 'WhatsApp',\n 'conversations.filter.sms': 'SMS',\n 'conversations.filter.instagram': 'Instagram',\n 'conversations.filter.email': 'E-mail',\n 'conversations.filter.webchat': 'Web',\n\n // Rótulos de status\n 'conversations.status.open': 'Aberta',\n 'conversations.status.snoozed': 'Adiada',\n 'conversations.status.closed': 'Encerrada',\n\n // Estado vazio\n 'conversations.empty.select': 'Selecione uma conversa para começar a conversar',\n\n // Thread\n 'conversations.thread.back': 'Voltar às conversas',\n 'conversations.thread.snooze': 'Adiar',\n 'conversations.thread.close': 'Encerrar',\n 'conversations.thread.details': 'Alternar detalhes do contato',\n 'conversations.thread.empty': 'Nenhuma mensagem ainda',\n 'conversations.thread.reply': 'Responder via {{channel}}…',\n 'conversations.thread.send': 'Enviar',\n\n // Painel do contato\n 'conversations.contact.details': 'Detalhes',\n 'conversations.contact.closeDetails': 'Fechar detalhes',\n 'conversations.contact.channel': 'Canal',\n 'conversations.contact.status': 'Status',\n 'conversations.filter.anyOwner': 'Qualquer dono',\n 'conversations.filter.noOwner': 'Sem dono',\n 'conversations.contact.leadOwner': 'Dono do lead',\n 'conversations.contact.assignedTo': 'Responsável',\n 'conversations.contact.location': 'Localização',\n 'conversations.contact.tags': 'Etiquetas',\n 'conversations.contact.note': 'Nota',\n 'conversations.contact.linkedRecords': 'Registros vinculados',\n 'conversations.contact.noLinkedRecords': 'Nenhum registro vinculado ainda.',\n\n // Modal de nova conversa\n 'conversations.new.title': 'Nova conversa',\n 'conversations.new.channel': 'Canal',\n 'conversations.new.contactName': 'Nome do contato',\n 'conversations.new.contactNamePlaceholder': 'ex.: Maria Silva',\n 'conversations.new.handle': 'Telefone / usuário / e-mail',\n 'conversations.new.handlePlaceholder': '+55 11 99999-0000',\n // O campo de handle só aparece quando o contato escolhido não tem o dado do\n // canal ativo — caso contrário ele é derivado e mostrado no chip.\n 'conversations.new.addHandle': 'Adicionar {label}',\n 'conversations.new.handleLabel.phone': 'telefone',\n 'conversations.new.handleLabel.email': 'e-mail',\n 'conversations.new.handleLabel.instagram': '@ do Instagram',\n 'conversations.new.handleLabel.webchat': 'id do chat',\n 'conversations.new.firstMessage': 'Primeira mensagem',\n 'conversations.new.firstMessagePlaceholder': 'Escreva a primeira mensagem (opcional)…',\n 'conversations.new.cancel': 'Cancelar',\n 'conversations.new.create': 'Iniciar conversa',\n 'conversations.new.creating': 'Iniciando…',\n 'conversations.new.createFailed': 'Não foi possível criar a conversa',\n\n // Painel — a fila de quem está esperando resposta\n 'conversations.dashboard.waiting': 'Esperando resposta',\n 'conversations.dashboard.waitingOldest': 'A mais antiga há {{time}}',\n 'conversations.dashboard.waitingNone': 'Ninguém na fila',\n 'conversations.dashboard.openThreads': 'Conversas abertas',\n 'conversations.dashboard.openThreadsSub': '{{count}} esperando resposta',\n 'conversations.dashboard.needsYou': 'Precisa de você',\n 'conversations.dashboard.needsYouEmpty': 'Ninguém esperando. Caixa de entrada em dia.',\n 'conversations.dashboard.who': 'Quem',\n 'conversations.dashboard.waited': 'Esperando há',\n 'conversations.waited.minutes': '{{count}} min',\n 'conversations.waited.hours': '{{count}} h',\n 'conversations.waited.days': '{{count}} d',\n\n // Configurações da caixa de entrada\n 'conversations.settings.title': 'Conversas',\n 'conversations.settings.channels': 'Seus números',\n 'conversations.settings.channelsHelp': 'Por onde a mensagem entra e sai. Ligue e gerencie os canais na aba Integrações.',\n 'conversations.settings.channelsEmpty': 'Nenhum canal ligado ainda — enquanto isso, a caixa de entrada fica vazia. Ligue o WhatsApp na aba Integrações.',\n 'conversations.settings.channelsUnavailable': 'Não foi possível consultar seus canais agora.',\n 'conversations.settings.channelDedicated': 'Número só seu',\n 'conversations.settings.channelShared': 'Número da plataforma',\n 'conversations.settings.status.active': 'Ativo',\n 'conversations.settings.status.requested': 'Solicitado',\n 'conversations.settings.status.provisioning': 'Provisionando',\n 'conversations.settings.status.provisioned': 'Provisionado',\n 'conversations.settings.status.verifying': 'Verificando',\n 'conversations.settings.status.failed': 'Falhou',\n 'conversations.settings.status.released': 'Devolvido',\n 'conversations.settings.status.disconnected': 'Desconectado',\n}\n","import { en } from './en'\nimport { ptBR } from './pt-BR'\n\nexport const conversationsLocales: Record<string, Record<string, string>> = {\n en,\n 'pt-BR': ptBR,\n}\n","import React, { useEffect, useMemo } from 'react'\nimport type { StoreApi } from 'zustand'\nimport type { DashboardWidgetDef } from '@fayz-ai/core'\nimport { useTranslation, navigateApp } from '@fayz-ai/core'\nimport {\n KpiCard, TableWidget, defineKpiWidget, defineTableWidget,\n type TableWidgetProps,\n} from '@fayz-ai/ui'\nimport {\n ConversationsContextProvider,\n useConversationsStore,\n type ResolvedConversationsConfig,\n} from '../context'\nimport type { ConversationsUIState } from '../store'\nimport { isWaitingOnUs, type Conversation } from '../types'\n\n// ---------------------------------------------------------------------------\n// Inbox widgets for the dashboard registry.\n//\n// This plugin registered nothing here until now, which meant the one number a\n// front desk actually opens the day for — \"who is waiting on me\" — existed on\n// no surface but the inbox itself. A dashboard that shows revenue and pipeline\n// while somebody has been waiting since Tuesday is reporting on the past.\n//\n// ── What \"waiting\" means ──────────────────────────────────────────────────\n//\n// `isWaitingOnUs` (see ../types), and not a rule spelled out again here: the\n// KPI, the table and anything that later filters the inbox have to agree, and a\n// dashboard that says three while the list shows one is worse than neither.\n//\n// It reads `lastMessageDirection`, which migration 001 added and a trigger\n// keeps current. The first pass of this file used `unreadCount > 0` because the\n// column did not exist — an approximation that missed the case that hurts\n// most: a thread somebody opened, read, meant to answer later and forgot. Zero\n// unread, customer still waiting. The fallback is still there for threads that\n// genuinely do not know their direction.\n// ---------------------------------------------------------------------------\n\n/** The store dedups the fetch, so every widget may ensure its own data. */\nfunction useEnsureConversations() {\n const load = useConversationsStore((s) => s.load)\n const loaded = useConversationsStore((s) => s.conversations.length > 0)\n useEffect(() => { if (!loaded) void load() }, [])\n}\n\nfunction useWaiting(): { waiting: Conversation[]; open: number; loading: boolean } {\n useEnsureConversations()\n const conversations = useConversationsStore((s) => s.conversations)\n const loading = useConversationsStore((s) => s.loading)\n return useMemo(() => {\n const open = conversations.filter((c) => c.status === 'open')\n const waiting = open\n .filter(isWaitingOnUs)\n // Oldest first: the list is a queue, and a queue that puts the newest\n // arrival on top is the reason somebody waits three days.\n .sort((a, b) => Date.parse(a.lastMessageAt) - Date.parse(b.lastMessageAt))\n return { waiting, open: open.length, loading }\n }, [conversations, loading])\n}\n\n/**\n * How long they have been waiting, in the coarsest unit that is still true.\n *\n * Minutes for the first hour, then hours, then days — an exact \"2h 14min\" reads\n * as precision about something nobody measures that finely, and it is one more\n * number to parse in a cell that exists to be scanned.\n */\nfunction waitedFor(iso: string, t: (key: string, vars?: Record<string, string>) => string): string {\n const ms = Date.now() - Date.parse(iso)\n if (!Number.isFinite(ms) || ms < 0) return '—'\n const minutes = Math.floor(ms / 60000)\n if (minutes < 60) return t('conversations.waited.minutes', { count: String(Math.max(minutes, 1)) })\n const hours = Math.floor(minutes / 60)\n if (hours < 24) return t('conversations.waited.hours', { count: String(hours) })\n return t('conversations.waited.days', { count: String(Math.floor(hours / 24)) })\n}\n\n// ---------------------------------------------------------------------------\n// KPIs\n// ---------------------------------------------------------------------------\n\nfunction WaitingKpi() {\n const t = useTranslation()\n const { waiting, loading } = useWaiting()\n const oldest = waiting[0]\n return (\n <KpiCard\n label={t('conversations.dashboard.waiting')}\n icon=\"MessageCircleWarning\"\n loading={loading && waiting.length === 0}\n value={String(waiting.length)}\n // The count alone does not say whether this is a busy morning or a\n // failure: three people waiting ten minutes is a queue, one person\n // waiting two days is an apology.\n sub={\n oldest\n ? t('conversations.dashboard.waitingOldest', { time: waitedFor(oldest.lastMessageAt, t) })\n : t('conversations.dashboard.waitingNone')\n }\n // More is worse here, so the arrow has to be read the other way round.\n invertTrend\n />\n )\n}\n\nfunction OpenThreadsKpi() {\n const t = useTranslation()\n const { open, waiting, loading } = useWaiting()\n return (\n <KpiCard\n label={t('conversations.dashboard.openThreads')}\n icon=\"MessagesSquare\"\n loading={loading && open === 0}\n value={String(open)}\n sub={t('conversations.dashboard.openThreadsSub', { count: String(waiting.length) })}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// The queue itself\n// ---------------------------------------------------------------------------\n\nfunction WaitingTable() {\n const t = useTranslation()\n const { waiting, loading } = useWaiting()\n\n // Column type borrowed from the widget that consumes it rather than from\n // @tanstack/react-table directly: this plugin has no table dependency of its\n // own, and adding one to name a type would put a second copy of the table\n // library in the tree of every app that installs the inbox.\n const columns = useMemo<TableWidgetProps<Conversation>['columns']>(() => [\n {\n accessorKey: 'contactName',\n header: t('conversations.dashboard.who'),\n cell: ({ row }) => (\n <span className=\"font-medium\">{row.original.contactName}</span>\n ),\n },\n {\n id: 'preview',\n header: '',\n // The message, not just the name: half of triage is deciding which of\n // five waiting people is the one worth answering first, and that is\n // decided by what they said.\n cell: ({ row }) => (\n <span className=\"line-clamp-1 text-xs text-muted-foreground\">{row.original.lastMessagePreview}</span>\n ),\n },\n {\n id: 'channel',\n header: t('conversations.contact.channel'),\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {t(`conversations.filter.${row.original.channel}`)}\n </span>\n ),\n },\n {\n id: 'waited',\n header: t('conversations.dashboard.waited'),\n cell: ({ row }) => (\n <span className=\"whitespace-nowrap text-xs font-medium tabular-nums\">\n {waitedFor(row.original.lastMessageAt, t)}\n </span>\n ),\n },\n ], [t])\n\n return (\n <TableWidget\n title={t('conversations.dashboard.needsYou')}\n icon=\"MessageCircleWarning\"\n columns={columns}\n data={waiting}\n loading={loading && waiting.length === 0}\n emptyMessage={t('conversations.dashboard.needsYouEmpty')}\n // Straight into the thread. A widget that names a person waiting and then\n // makes you go find them in a list is a notification, not a queue.\n onRowClick={(row) => { navigateApp(`/conversations?thread=${row.id}`) }}\n />\n )\n}\n\n// ---------------------------------------------------------------------------\n// Registry builder — each widget carries its own provider, so it renders on the\n// app home with no inbox page around it.\n// ---------------------------------------------------------------------------\n\nexport function createConversationsDashboardWidgets(ctx: {\n store: StoreApi<ConversationsUIState>\n config: ResolvedConversationsConfig\n}): DashboardWidgetDef[] {\n const withCtx = (Inner: React.ComponentType): React.ComponentType<unknown> => {\n const Wrapped = () => (\n <ConversationsContextProvider store={ctx.store} config={ctx.config}>\n <Inner />\n </ConversationsContextProvider>\n )\n Wrapped.displayName = `ConversationsWidget(${Inner.displayName ?? Inner.name})`\n return Wrapped\n }\n\n return [\n // Visible on the home by DEFAULT, unlike most plugin widgets. The rest of\n // the registry is opt-in because a dashboard of everything is a dashboard\n // of nothing — but an unanswered customer is the one item on any home\n // screen that is time-critical, and hiding it behind Customize means it\n // only reaches the people who already knew to look.\n defineKpiWidget({\n id: 'conversations.kpi.waiting',\n title: 'conversations.dashboard.waiting',\n domain: 'conversations',\n defaultOrder: -1,\n component: withCtx(WaitingKpi),\n }),\n defineKpiWidget({\n id: 'conversations.kpi.open',\n title: 'conversations.dashboard.openThreads',\n domain: 'conversations',\n defaultOrder: 4,\n defaultVisible: false,\n component: withCtx(OpenThreadsKpi),\n }),\n defineTableWidget({\n id: 'conversations.table.waiting',\n title: 'conversations.dashboard.needsYou',\n domain: 'conversations',\n span: 2,\n defaultOrder: 10,\n component: withCtx(WaitingTable),\n }),\n ]\n}\n","import { countByTenant, type OnboardingProgramDef } from '@fayz-ai/core'\nimport { T } from '../data/tables'\n\n/**\n * Implantação da caixa de entrada — um canal e um hábito.\n *\n * Ordem 30, à frente da base do workspace (50) e do CRM (80), e isso é uma\n * opinião: numa operação que atende, o cliente escreve antes de qualquer outra\n * coisa acontecer. Convidar a equipe e desenhar o funil são trabalho de quem já\n * tem alguém escrevendo; ligar o canal é o que faz aparecer o primeiro.\n *\n * Dois passos, e o segundo não é uma tela. A caixa de entrada é o módulo que\n * mais parece pronto vazio: ela abre, tem filtro por canal, tem busca — e não\n * chega mensagem nenhuma porque ninguém ligou o número. O passo que fecha é o\n * único que prova que o caminho inteiro existe: uma mensagem que entrou e foi\n * respondida daqui.\n */\nexport function buildConversationsOnboarding(): OnboardingProgramDef {\n return {\n id: 'conversations',\n title: 'Quem fala com você',\n order: 30,\n role: 'frontdesk',\n instructions: `Você está ligando a caixa de entrada. O risco aqui não é a pessoa não achar a tela — é ela achar a tela, ver que está vazia e concluir que o produto não funciona.\n\n- Comece pelo CANAL. Sem número ligado não entra mensagem nenhuma, e todo o resto do módulo é decoração. O caminho é Configurações › Conversas › Integrações.\n- Explique a diferença entre o número da plataforma e um número dedicado ANTES de ela escolher: no compartilhado ela já começa a receber hoje; no dedicado sai o nome dela, mas ainda passa por um cadastro na Meta.\n- O segundo passo é a prova: peça para ela mandar uma mensagem do próprio celular para o número e responder daqui. É o que mostra que ida e volta funcionam.\n- Se ela já tem WhatsApp Business no celular, diga com todas as letras o que muda: as conversas passam a ficar aqui, onde a equipe inteira vê, em vez de num aparelho só.`,\n steps: [\n {\n key: 'channel',\n title: 'Ligue o canal onde seu cliente já fala',\n description: 'Sem número conectado, a caixa de entrada abre vazia para sempre.',\n icon: 'MessageCircle',\n route: '/settings/conversations/_integrations',\n priority: 'urgent',\n // O passo É a tela: um app que monte o inbox sem a rota de configurações\n // não tem onde ligar canal nenhum, e a linha ficaria aberta para sempre.\n requiresRoute: true,\n agentHint:\n 'Abra Integrações e apresente as duas opções pelo que elas custam à pessoa HOJE: o número da plataforma começa a receber agora, o dedicado sai com o nome dela mas espera o cadastro na Meta.',\n howTo:\n 'Configurações › Conversas › Integrações › Tyxter. O número da plataforma já está ligado e é compartilhado com outros negócios — dá para começar a receber por ele hoje. Um número dedicado sai só com o seu nome, libera os seus próprios modelos de mensagem e tem limite de envio próprio; ele é alugado no mês e ainda passa por um cadastro rápido na Meta antes do primeiro envio.',\n celebrate: 'Canal ligado — agora dá para te acharem 📲',\n script: [\n { kind: 'goto', route: '/settings/conversations/_integrations' },\n {\n kind: 'ask',\n text: 'Estamos nas Integrações da caixa de entrada. Mostre o número da plataforma e o dedicado, explique o que muda em cada um e ajude a pessoa a escolher.',\n },\n ],\n check: async () => (await countByTenant(T.channels)) > 0,\n },\n {\n key: 'first-reply',\n title: 'Receba e responda a primeira mensagem',\n description: 'A prova de que a ida e a volta funcionam.',\n icon: 'Send',\n route: '/conversations',\n priority: 'high',\n agentHint:\n 'Não é passo de cadastro. Peça para a pessoa mandar uma mensagem do próprio celular para o número ligado e responder aqui de dentro — e fique com ela até a resposta chegar do outro lado.',\n howTo:\n 'Pegue o seu celular, mande uma mensagem qualquer para o número que você acabou de ligar e volte aqui: a conversa aparece em Conversas. Responda por aqui e confira que chegou no celular. É o teste que prova que a caixa de entrada está no ar — e é também como a equipe vai trabalhar todo dia, com a conversa num lugar que todo mundo vê em vez de num aparelho só.',\n celebrate: 'Ida e volta funcionando 💬',\n // A conversa existe assim que a primeira mensagem entra, então a\n // contagem de threads é a checagem — e não a de mensagens, que seria\n // fechada por um envio que ninguém respondeu.\n check: async () => (await countByTenant(T.conversations)) > 0,\n },\n ],\n }\n}\n","// The one place that names the Tyxter number-claim data plane.\n//\n// Kept apart from connectorDef.tsx for the reason data.ts exists on the Kiwify\n// and Stripe connectors: the credential path is the half that moves when the\n// platform broker lands, and when it does only this file should change.\nimport {\n CONNECTOR_RUNTIME_TOKEN_HEADER,\n connectorRuntimeToken,\n getSupabaseClientOptional,\n} from '@fayz-ai/core'\n\n/** The edge function that holds every phone-number call this connector makes. */\nexport const TYXTER_NUMBER_CLAIM_FUNCTION = 'tyxter-number-claim'\n\n/** The channel row, as the function hands it back. A subset of the table on purpose. */\nexport interface ClaimedChannel {\n id: string\n channel: string\n provider: string\n /** Null while the row is still a reservation with no number behind it. */\n providerNumberId: string | null\n phoneE164: string | null\n kind: string\n status: string\n displayName: string | null\n}\n\n/**\n * Where to send the human to finish the Meta registration, and how good the\n * link is.\n *\n * `source` is surfaced rather than hidden because the three are not equivalent:\n * 'session' returns the person to this very panel and names the tenant to Meta;\n * 'error_link' is the provider's own pre-targeted page; 'default' is the generic\n * dashboard, which works but assumes the browser is signed into the right\n * organization. The panel says less when the source is worse.\n */\nexport interface MetaRegistrationHandoff {\n source: 'session' | 'error_link' | 'default'\n url: string\n note: string | null\n sessionId?: string\n expiresAt?: string | null\n}\n\nexport interface ClaimResult {\n channel: ClaimedChannel\n metaRegistration: MetaRegistrationHandoff | null\n}\n\ninterface MinimalClient {\n functions: {\n invoke: (\n name: string,\n options: { body: unknown; headers?: Record<string, string> },\n ) => Promise<{ data: unknown; error: { message: string } | null }>\n }\n}\n\nfunction client(): MinimalClient {\n const supabase = getSupabaseClientOptional() as MinimalClient | null\n if (!supabase) throw new Error('Sem conexão com o banco para falar com a Tyxter.')\n return supabase\n}\n\n/**\n * One call to the data plane.\n *\n * The Supabase session rides in `Authorization` — the gateway checks it, and the\n * function re-checks membership in the tenant against it, because renting a\n * number costs money every month.\n *\n * The runtime token is BEST-EFFORT here, unlike on Kiwify. There it identifies\n * whose credential to redeem and a call without it is unanswerable; here the\n * credential is the platform's own, held once for the whole product, and the\n * function falls back to machine redemption keyed by the tenant. An app that\n * installed no token source can still claim a number, which is the right\n * outcome — refusing would be enforcing a requirement that does not exist.\n */\nasync function invoke<T>(body: Record<string, unknown>): Promise<T> {\n let headers: Record<string, string> | undefined\n try {\n headers = { [CONNECTOR_RUNTIME_TOKEN_HEADER]: await connectorRuntimeToken({ tenantId: String(body.tenantId ?? '') }) }\n } catch {\n headers = undefined\n }\n\n const { data, error } = await client().functions.invoke(TYXTER_NUMBER_CLAIM_FUNCTION, {\n body,\n ...(headers ? { headers } : {}),\n })\n if (error) throw new Error(error.message)\n return data as T\n}\n\n/**\n * A page address, cleaned up for `return_url`.\n *\n * The provider's allowlist refuses a URL carrying a fragment, credentials or a\n * non-https scheme, so the fragment goes — and this app is a hash router, which\n * means the fragment is the WHOLE route. Losing it returns the human to the\n * app's front door rather than to this panel, which is a smaller failure than a\n * session the provider refuses to create at all.\n */\nexport function returnUrlFrom(href: string | null | undefined): string | null {\n if (!href) return null\n try {\n const url = new URL(href)\n url.hash = ''\n url.username = ''\n url.password = ''\n return url.toString()\n } catch {\n return null\n }\n}\n\n/** The page the human is standing on, as a `return_url` the provider will accept. */\nexport function currentReturnUrl(): string | null {\n return typeof window === 'undefined' ? null : returnUrlFrom(window.location.href)\n}\n\n/** Rent a dedicated number for this tenant, in the given area code. */\nexport function claimDedicatedNumber(input: { tenantId: string; ddd: string }): Promise<ClaimResult> {\n return invoke<ClaimResult>({\n action: 'claim',\n tenantId: input.tenantId,\n ddd: input.ddd,\n returnUrl: currentReturnUrl(),\n })\n}\n\n/**\n * Re-read the tenant's numbers at the provider and sync the rows.\n *\n * The poll the panel runs while a claim is pending. It is not redundant with the\n * webhook: four of the five lifecycle steps emit no event at all (verified\n * live — a full provision to `active` produced zero `phone_number.*` events), so\n * without this the row would sit on \"Solicitado\" until the day the number is\n * disconnected.\n */\nexport function refreshDedicatedNumbers(tenantId: string): Promise<{ channels: ClaimedChannel[] }> {\n return invoke<{ channels: ClaimedChannel[] }>({ action: 'status', tenantId })\n}\n\n/** The link that hands the human to Meta's Embedded Signup, which no key can do headlessly. */\nexport function metaRegistrationHandoff(tenantId: string): Promise<{\n metaRegistration: MetaRegistrationHandoff | null\n channel: ClaimedChannel\n}> {\n return invoke({ action: 'handoff', tenantId, returnUrl: currentReturnUrl() })\n}\n","// \"Can this app take a Pix inside a conversation?\" — asked from the browser,\n// answered by the provider.\n//\n// It is a function call and not a table read because the answer does not live in\n// this pool. It lives at the provider, behind the PLATFORM's key, which a\n// browser must never hold — so `tyxter-payment-preflight` asks on the panel's\n// behalf and hands back only the verdict. There is nothing to cache here: a\n// merchant who has just finished the credential handoff is exactly the person\n// pressing the button again.\nimport { getActiveTenantId, getSupabaseClientOptional } from '@fayz-ai/core'\n\n/** The edge function that holds both questions. */\nexport const PAYMENT_PREFLIGHT_FUNCTION = 'tyxter-payment-preflight'\n\n/**\n * Which rail is actually behind the payments channel.\n *\n * The distinction that matters and is easy to collapse: `sandbox_default` is\n * READY — charges open, settle and fire webhooks — but the money is not real,\n * and the transparent-Pix provider options are refused. A green badge over it\n * is how a salon finds out on the day of its first real charge, so the panel\n * says \"sandbox\" beside the tick instead.\n */\nexport type PaymentActiveMode = 'sandbox_default' | 'iniciador' | 'abacate_pay'\n\nexport interface PaymentReadiness {\n /** The provider's own verdict. True for the sandbox fixture too — see `sandbox`. */\n ready: boolean\n status: string\n mode: PaymentActiveMode | null\n /** `mode === 'sandbox_default'`: ready, but not with real money. */\n sandbox: boolean\n environment: string | null\n /** Why not, when the provider says why. */\n reason: string | null\n}\n\n/** The browser handoff where the merchant enters credentials this app never sees. */\nexport interface PaymentSetupSession {\n setupUrl: string | null\n requestId: string | null\n expiresAt: string | null\n environment: string | null\n}\n\ninterface MinimalClient {\n functions: {\n invoke: (\n name: string,\n options: { body: unknown },\n ) => Promise<{ data: unknown; error: { message: string } | null }>\n }\n}\n\nasync function invoke<T>(body: Record<string, unknown>, tenantId?: string): Promise<T> {\n const supabase = getSupabaseClientOptional() as MinimalClient | null\n if (!supabase) throw new Error('Sem conexão com o banco para verificar os pagamentos.')\n const tenant = tenantId ?? getActiveTenantId()\n if (!tenant) throw new Error('Sem negócio selecionado.')\n\n const { data, error } = await supabase.functions.invoke(PAYMENT_PREFLIGHT_FUNCTION, {\n body: { ...body, tenantId: tenant },\n })\n if (!error) return data as T\n\n // supabase-js buries the function's own body in the error context. Without\n // digging it out every refusal reads as \"Edge Function returned a non-2xx\n // status code\", which is what \"not connected\", \"no key\" and a CORS preflight\n // all look like — while the function answered each with a sentence.\n let message = ''\n try {\n const payload = (await (error as { context?: { json?: () => Promise<unknown> } })\n ?.context?.json?.()) as { message?: string; error?: string } | undefined\n message = String(payload?.message ?? payload?.error ?? '').trim()\n } catch {\n /* no JSON body */\n }\n throw new Error(message || error.message)\n}\n\nexport async function readPaymentReadiness(tenantId?: string): Promise<PaymentReadiness> {\n const answer = await invoke<{ payments: PaymentReadiness }>({ action: 'status' }, tenantId)\n return answer.payments\n}\n\nexport async function openPaymentSetupSession(tenantId?: string): Promise<PaymentSetupSession> {\n return await invoke<PaymentSetupSession>({ action: 'connect' }, tenantId)\n}\n\n/**\n * Is the `pay` action safe to offer in a message template?\n *\n * The sandbox fixture counts, deliberately: a build being dogfooded on sandbox\n * credentials must be able to exercise the whole flow, and the panel is where\n * the \"sandbox\" qualifier is shown. What is refused is a channel with nothing\n * selected behind it, where a Pix button would produce a charge that never opens.\n */\nexport function canOfferPayment(readiness: PaymentReadiness | null): boolean {\n if (!readiness?.ready) return false\n return readiness.mode !== null\n}\n","// Tyxter — WhatsApp as a channel of the inbox, and the first messaging\n// connector on the standard (docs/integrations/CONNECTORS.md).\n//\n// It is the connector with NO connect form at all, and that is the whole design\n// rather than an omission. FayaLabs holds one Tyxter project per product and\n// one dashboard key with it; a tenant gets WhatsApp by agreeing to use it, not\n// by going to find a key that was never issued to them. So `fields` is empty,\n// no credential sink is involved, and connecting writes one thing: the\n// connections row that says this tenant switched it on. The key is redeemed\n// server-side, per call, by the edge functions that land in WP3–WP6.\n//\n// `authKind: 'api-key'` still, and not 'oauth': Tyxter has no consent screen and\n// no app to install, so declaring OAuth would ship a button with no flow behind\n// it (the Bling failure named in the standard).\n//\n// No SQL of its own for the CONNECTION — that is a connections row (029).\n// The table this plugin does add, plg_conversations_channels, is not connection\n// state: it is which phone number a message leaves by, which outlives any one\n// connector and is read by the inbox itself.\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport { ExternalLink, Loader2 } from 'lucide-react'\nimport { Button, Input, toast } from '@fayz-ai/ui'\nimport {\n connectionRuns,\n connectionStatus,\n createConnectionStore,\n useActiveTenantId,\n type ConnectorDefinition,\n describeError,\n} from '@fayz-ai/core'\nimport {\n CHANNEL_CLAIM_TIMELINE,\n canClaimDedicated,\n findDedicatedChannel,\n findFallbackChannel,\n isPendingChannelStatus,\n listMessagingChannels,\n type MessagingChannelAccount,\n type MessagingChannelStatus,\n} from '../../data/channels'\nimport {\n claimDedicatedNumber,\n metaRegistrationHandoff,\n refreshDedicatedNumbers,\n type MetaRegistrationHandoff,\n} from './data'\nimport {\n canOfferPayment,\n openPaymentSetupSession,\n readPaymentReadiness,\n type PaymentReadiness,\n} from '../../data/payment-preflight'\n\nexport const TYXTER_CONNECTOR_ID = 'tyxter'\n\n/**\n * Four seconds.\n *\n * Nobody is staring at a spinner here — the caller is an automation reacting to\n * a booking — but the budget is what stops a slow provider from holding the\n * automation executor's worker while the next twenty events queue behind it.\n * Tyxter answers `POST /v1/messages` with a 202 and does the delivery\n * asynchronously, so the call being timed is an accept, not a send.\n */\nexport const TYXTER_LATENCY_BUDGET_MS = 4000\n\n// One account per tenant: the platform's project is the same one for everybody,\n// and what the row records is consent, so there is no instance to key on.\nconst store = createConnectionStore(TYXTER_CONNECTOR_ID)\n\nconst KIND_LABEL: Record<MessagingChannelAccount['kind'], string> = {\n fallback: 'Número da plataforma',\n dedicated: 'Número dedicado',\n}\n\nconst STATUS_LABEL: Record<MessagingChannelAccount['status'], string> = {\n requested: 'Solicitado',\n provisioning: 'Em preparação',\n provisioned: 'Preparado',\n verifying: 'Em verificação',\n active: 'Ativo',\n failed: 'Falhou',\n released: 'Liberado',\n disconnected: 'Desconectado',\n}\n\n/** How long between polls while a claim is on its way. */\nconst POLL_INTERVAL_MS = 5000\n\n/**\n * The lifecycle, drawn.\n *\n * Five steps and only the last one sends. Drawn as a list rather than a single\n * badge because the wait is the thing being explained: a person who asked for a\n * phone line and sees \"Em preparação\" for two minutes needs to know how many\n * steps are left, not just which one is current.\n */\nfunction ClaimTimeline({ status }: { status: MessagingChannelStatus }) {\n if (status === 'failed' || status === 'released' || status === 'disconnected') {\n return (\n <p className=\"text-xs text-destructive\">\n {status === 'failed'\n ? 'O pedido não foi concluído. Você pode tentar de novo.'\n : `Este número saiu do ar (${STATUS_LABEL[status]}).`}\n </p>\n )\n }\n const current = CHANNEL_CLAIM_TIMELINE.indexOf(status)\n return (\n <ol className=\"space-y-1\">\n {CHANNEL_CLAIM_TIMELINE.map((step, index) => {\n const done = current > index\n const now = current === index\n return (\n <li\n key={step}\n className={`flex items-center gap-2 text-xs ${\n now ? 'font-medium text-foreground' : done ? 'text-muted-foreground' : 'text-muted-foreground/60'\n }`}\n >\n <span aria-hidden className={`h-1.5 w-1.5 rounded-full ${done || now ? 'bg-primary' : 'bg-border'}`} />\n {STATUS_LABEL[step]}\n {now && status !== 'active' && <Loader2 className=\"h-3 w-3 animate-spin\" />}\n </li>\n )\n })}\n </ol>\n )\n}\n\n/**\n * The handoff a machine cannot make.\n *\n * A rented number is not a registered one: Meta has never seen it, and WhatsApp\n * Embedded Signup is a browser window a person clicks through — the provider's\n * own connect endpoint refuses a Salvy number with `meta_registration_required`\n * and says there is no headless equivalent. So this is the honest end of the\n * flow, and it is prominent rather than tucked away, because a claim that stops\n * here without saying so looks like a claim that worked.\n */\nfunction MetaRegistrationCard({ handoff }: { handoff: MetaRegistrationHandoff }) {\n return (\n <div className=\"space-y-2 rounded-md border border-primary/40 bg-primary/5 p-3\">\n <p className=\"text-xs font-medium text-foreground\">Falta liberar o número na Meta</p>\n <p className=\"text-xs text-muted-foreground\">\n O número já é seu, mas ainda não pode enviar: a Meta exige que alguém conclua o cadastro do\n WhatsApp numa janela do navegador. É rápido, e só precisa ser feito uma vez.\n </p>\n <Button asChild size=\"sm\">\n <a href={handoff.url} target=\"_blank\" rel=\"noopener noreferrer\">\n Concluir cadastro na Meta\n <ExternalLink className=\"ml-1.5 h-3.5 w-3.5\" />\n </a>\n </Button>\n {handoff.source === 'default' && (\n <p className=\"text-[11px] text-muted-foreground\">\n Confira se a conta aberta no navegador é a certa antes de concluir.\n </p>\n )}\n </div>\n )\n}\n\n/**\n * Can the customer pay inside the conversation, and if not, what has to happen?\n *\n * The answer is not in this pool. It is at the provider, behind the platform's\n * key, so `tyxter-payment-preflight` asks and this renders the verdict. Three\n * states and they are deliberately not two:\n *\n * ready, real a payment connection is selected. Nothing to do.\n * ready, sandbox charges open and settle, with money that is not real.\n * Shown as ready WITH the word \"sandbox\", because a green\n * tick over a fixture is discovered on the day of the first\n * real charge.\n * not ready the handoff button, which opens a session at the provider\n * rather than linking to a dashboard the merchant then has\n * to navigate.\n *\n * The credentials are typed at the provider and never reach this app. That is\n * the accepted redundancy with the app's own AbacatePay connector, and it is\n * also the reason this panel has no form: a secret that never enters the\n * product is one the product cannot leak.\n */\nfunction TyxterPaymentsPanel() {\n const [readiness, setReadiness] = useState<PaymentReadiness | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [loading, setLoading] = useState(true)\n const [handoff, setHandoff] = useState<string | null>(null)\n const [opening, setOpening] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n void readPaymentReadiness()\n .then((value) => { if (!cancelled) setReadiness(value) })\n .catch((caught: unknown) => {\n if (!cancelled) setError(describeError(caught, 'Não deu para verificar agora.'))\n })\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [])\n\n const connect = async () => {\n setOpening(true)\n setError(null)\n try {\n const session = await openPaymentSetupSession()\n setHandoff(session.setupUrl)\n // Opened by the merchant and not by us: a popup fired from an async\n // callback is the one a browser blocks, and a blocked popup reads as a\n // button that does nothing.\n } catch (caught) {\n setError(describeError(caught, 'Não deu para abrir a configuração.'))\n } finally {\n setOpening(false)\n }\n }\n\n const ready = canOfferPayment(readiness)\n\n return (\n <div className=\"space-y-3 border-t pt-4\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Pagamento no WhatsApp</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Com isso ligado, o cliente recebe o Pix na própria conversa e o agendamento fica marcado\n como pago sozinho.\n </p>\n </div>\n\n {loading && <p className=\"text-xs text-muted-foreground\">Verificando…</p>}\n\n {!loading && ready && (\n <p className=\"text-xs text-foreground\">\n <span className=\"font-medium text-emerald-600\">Pronto para cobrar</span>\n {readiness?.sandbox && (\n <span className=\"ml-2 rounded bg-amber-100 px-1.5 py-0.5 text-[11px] font-medium text-amber-800\">\n sandbox — o dinheiro não é real\n </span>\n )}\n </p>\n )}\n\n {!loading && !ready && (\n <div className=\"space-y-2\">\n <p className=\"text-xs text-muted-foreground\">\n Ainda não dá para cobrar por aqui. A conta de pagamento é configurada na Tyxter, em uma\n página deles — a sua chave não passa por este app.\n {readiness?.reason ? ` (${readiness.reason})` : ''}\n </p>\n {handoff ? (\n <a\n href={handoff}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-block rounded-md border px-3 py-1.5 text-xs font-medium hover:bg-muted\"\n >\n Abrir a configuração de pagamento →\n </a>\n ) : (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => { void connect() }} disabled={opening}>\n {opening ? 'Abrindo…' : 'Configurar pagamento'}\n </Button>\n )}\n </div>\n )}\n\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n </div>\n )\n}\n\n/**\n * Which numbers this tenant sends by, and the button that gets it one of its own.\n *\n * ── Why this polls ──────────────────────────────────────────────────────────\n * Verified against the provider's sandbox on 2026-08-24: provisioning a number\n * walked requested → provisioned → verifying → active in about a second and\n * emitted ZERO `phone_number.*` webhooks. The deliverable events are verified /\n * disconnected / released / quality_changed / messaging_limit_*, and none of\n * them fired. So the webhook (WP4) is not the mechanism that advances a claim —\n * asking is, and this panel asks every few seconds while the row is pending and\n * stops the moment it is not.\n */\nfunction TyxterExtraPanel() {\n const tenantId = useActiveTenantId()\n const [channels, setChannels] = useState<MessagingChannelAccount[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [ddd, setDdd] = useState('')\n const [claiming, setClaiming] = useState(false)\n const [handoff, setHandoff] = useState<MetaRegistrationHandoff | null>(null)\n const mounted = useRef(true)\n\n useEffect(() => {\n mounted.current = true\n return () => { mounted.current = false }\n }, [])\n\n const load = useCallback(async () => {\n try {\n const rows = await listMessagingChannels({ provider: TYXTER_CONNECTOR_ID, channel: 'whatsapp' })\n if (mounted.current) { setChannels(rows); setError(null) }\n } catch {\n if (mounted.current) setError('Não conseguimos ler os números agora.')\n }\n }, [])\n\n useEffect(() => { void load() }, [load])\n\n const dedicated = channels ? findDedicatedChannel(channels, tenantId) : null\n const fallback = channels ? findFallbackChannel(channels) : null\n const pending = dedicated ? isPendingChannelStatus(dedicated.status) : false\n\n // The poll, and the reason it is keyed on `pending`: a screen that keeps\n // asking after the answer arrived is a cost with no reader.\n useEffect(() => {\n if (!pending || !tenantId) return undefined\n const timer = setInterval(() => {\n void refreshDedicatedNumbers(tenantId).then(() => load()).catch(() => {})\n }, POLL_INTERVAL_MS)\n return () => clearInterval(timer)\n }, [pending, tenantId, load])\n\n // The link is asked for once the number exists and while it cannot send.\n // Not during the wait — there is nothing to register yet — and not once the\n // row carries a Meta id, because asking then costs two provider calls per\n // per panel open to be told what the row already said.\n const registered = !!dedicated?.metadata?.meta_phone_number_id\n useEffect(() => {\n if (!tenantId || !dedicated || dedicated.status !== 'active' || registered || handoff) return\n void metaRegistrationHandoff(tenantId)\n .then((answer) => { if (mounted.current) setHandoff(answer.metaRegistration) })\n .catch(() => {})\n }, [tenantId, dedicated, registered, handoff])\n\n const canClaim = !!channels && !!tenantId && canClaimDedicated(channels, tenantId)\n\n async function onClaim() {\n if (!tenantId || !/^\\d{2}$/.test(ddd)) return\n setClaiming(true)\n try {\n const result = await claimDedicatedNumber({ tenantId, ddd })\n setHandoff(result.metaRegistration)\n setDdd('')\n await load()\n toast.success('Número solicitado. Acompanhe aqui o andamento.')\n } catch (caught) {\n toast.error(describeError(caught, 'Não foi possível pedir o número.'))\n } finally {\n if (mounted.current) setClaiming(false)\n }\n }\n\n return (\n <div className=\"space-y-3\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Números</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Por onde as suas mensagens de WhatsApp saem hoje.\n </p>\n </div>\n\n {error && <p className=\"text-xs text-destructive\">{error}</p>}\n\n {channels && channels.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">\n Nenhum número configurado ainda. Assim que a plataforma liberar o número compartilhado,\n ele aparece aqui.\n </p>\n )}\n\n {channels && channels.length > 0 && (\n <ul className=\"space-y-2\">\n {channels.map((channel) => (\n <li\n key={channel.id}\n className=\"flex flex-wrap items-baseline justify-between gap-2 rounded-md border bg-muted/30 p-3 text-xs\"\n >\n <span className=\"font-medium text-foreground\">\n {channel.phoneE164 ?? channel.providerNumberId}\n </span>\n <span className=\"text-muted-foreground\">\n {KIND_LABEL[channel.kind]} · {STATUS_LABEL[channel.status]}\n </span>\n </li>\n ))}\n </ul>\n )}\n\n {dedicated && (\n <div className=\"space-y-2 rounded-md border p-3\">\n <p className=\"text-xs font-medium text-foreground\">Seu número dedicado</p>\n <ClaimTimeline status={dedicated.status} />\n {dedicated.status === 'active' && !handoff && (\n <p className=\"text-xs text-muted-foreground\">\n Ativo. As suas mensagens saem por ele, com o seu nome e sem dividir com ninguém.\n </p>\n )}\n </div>\n )}\n\n {handoff && <MetaRegistrationCard handoff={handoff} />}\n\n {canClaim && (\n <div className=\"space-y-2 border-t pt-3\">\n <p className=\"text-xs font-medium text-foreground\">Quer um número só seu?</p>\n <p className=\"text-xs text-muted-foreground\">\n {fallback\n ? 'Hoje as suas mensagens saem pelo número da plataforma, dividido com outros negócios. Um número dedicado sai só com o seu nome, libera os seus próprios modelos de mensagem e tem limite de envio próprio.'\n : 'Um número dedicado sai só com o seu nome e tem limite de envio próprio.'}\n </p>\n <div className=\"flex items-end gap-2\">\n <label className=\"text-xs text-muted-foreground\">\n DDD\n <Input\n value={ddd}\n onChange={(e) => setDdd(e.target.value.replace(/\\D/g, '').slice(0, 2))}\n inputMode=\"numeric\"\n placeholder=\"21\"\n className=\"mt-1 w-20\"\n aria-label=\"DDD do número dedicado\"\n />\n </label>\n <Button size=\"sm\" disabled={claiming || !/^\\d{2}$/.test(ddd)} onClick={() => void onClaim()}>\n {claiming && <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" />}\n Solicitar número dedicado\n </Button>\n </div>\n <p className=\"text-[11px] text-muted-foreground\">\n O número é alugado no mês e, depois que chegar, ainda precisa de um cadastro rápido na\n Meta para começar a enviar.\n </p>\n </div>\n )}\n\n <TyxterPaymentsPanel />\n </div>\n )\n}\n\nexport const tyxterConnectorDef: ConnectorDefinition = {\n id: TYXTER_CONNECTOR_ID,\n hostPluginId: 'conversations',\n name: 'Tyxter',\n description:\n 'WhatsApp já pronto: confirmações e lembretes saem por um número da plataforma, e a resposta do cliente cai na sua caixa de entrada.',\n icon: 'MessageCircle',\n logoUrl: 'https://assets.fayz.ai/connectors/tyxter.png',\n category: 'messaging',\n authKind: 'api-key',\n // Sending is in line with the automation that asked for it; the reply, the\n // delivery status and the template approvals arrive later and file runs.\n planes: ['request', 'sync'],\n direction: 'outbound',\n docsUrl: 'https://tyxter.com/docs',\n // A message that does not go out must never take the booking with it. The\n // opposite verdict from a payment gateway, and for the opposite reason.\n latencyBudgetMs: TYXTER_LATENCY_BUDGET_MS,\n onFailure: 'degrade',\n permissions: [\n {\n kind: 'data',\n resource: 'conversation',\n actions: ['read', 'write'],\n reason:\n 'Abrir a conversa do cliente no WhatsApp e mantê-la em dia — é onde a mensagem enviada e a resposta dele ficam juntas.',\n },\n {\n kind: 'data',\n resource: 'message',\n actions: ['read', 'write'],\n reason:\n 'Guardar cada mensagem enviada e recebida, com o status que o WhatsApp devolve (enviada, entregue, lida).',\n },\n {\n kind: 'data',\n resource: 'message_template',\n actions: ['read', 'write'],\n reason:\n 'Ler os modelos de mensagem deste app e guardar o que a Meta respondeu sobre cada um: aprovado, recusado ou pausado.',\n },\n ],\n // No form: the key is the platform's. The connect step says so on its own\n // (`connectors.authorize.nothingToFill`) rather than drawing an empty grid.\n fields: [],\n invokedAt: [\n {\n key: 'messaging.send',\n label: 'Uma automação dispara e a mensagem sai no WhatsApp do cliente',\n touches: ['conversation', 'message'],\n },\n {\n key: 'conversations.inbound',\n label: 'O cliente responde, e a resposta entra na caixa de entrada',\n plane: 'sync',\n trigger: 'webhook',\n touches: ['conversation', 'message'],\n },\n {\n key: 'messaging.template_sync',\n label: 'Os modelos de mensagem vão para aprovação da Meta e o resultado volta para cá',\n plane: 'sync',\n trigger: 'scheduled',\n touches: ['message_template'],\n },\n ],\n howItSyncs: [\n 'As mensagens saem por um número de WhatsApp da plataforma, que já vem pronto — você não cadastra chave nenhuma nem precisa de um chip só seu.',\n 'Como esse número é dividido com outros negócios, o nome do seu vai escrito no começo da mensagem, e só modelos já aprovados pela Meta podem sair por ele.',\n 'Se você pedir um número dedicado, ele passa a ser o remetente assim que ficar ativo — aí a mensagem sai só com o seu nome e nada mais é dividido.',\n 'A resposta do cliente volta para Conversas em segundos, e botões como Confirmar e Cancelar já atualizam o agendamento sozinhos.',\n ],\n ...connectionStatus(\n TYXTER_CONNECTOR_ID,\n (connection) => ({ connected: !!connection?.active, plane: 'request' }),\n { store: () => store },\n ),\n ...connectionRuns(store),\n // Nothing to receive: the hub split out a credential half that does not exist\n // for this connector, so `values` is empty and consent is the whole act.\n saveConnection: async () => {\n await store.save({ active: true })\n },\n disconnect: () => store.disconnect(),\n disconnectNote:\n 'Desconectar para de enviar e de receber mensagens no WhatsApp. As conversas que já existem continuam aqui.',\n ExtraPanel: TyxterExtraPanel,\n}\n","import { defineSettingsTab } from '@fayz-ai/admin'\nimport { tl } from '@fayz-ai/core'\n\nexport const conversationsV1SettingsTabs = [\n defineSettingsTab({\n id: 'conversations-atendeai',\n label: 'AtendeAI',\n icon: 'Bot',\n section: 'communication',\n requiresFacet: 'atendeai',\n pending: true,\n defaults: {\n 'atendeai.assistant_name': 'Assistente', 'atendeai.tone': 'friendly',\n 'atendeai.ai_disclosure': true, 'atendeai.max_messages_per_conversation': 30, 'atendeai.escalation_timeout_minutes': 30,\n },\n sections: [\n { title: tl('General', 'Geral'), fields: [\n { key: 'atendeai.assistant_name', type: 'string', label: tl('Assistant name', 'Nome do assistente') },\n { key: 'atendeai.ai_disclosure', type: 'boolean', label: tl('Say it is an AI', 'Avisar que é uma inteligência artificial') },\n ] },\n { title: tl('Personality', 'Personalidade'), fields: [\n { key: 'atendeai.tone', type: 'select', label: tl('Tone', 'Tom'), options: [\n { value: 'friendly', label: tl('Friendly', 'Amigável') }, { value: 'formal', label: tl('Formal', 'Formal') }, { value: 'casual', label: tl('Casual', 'Descontraído') },\n ] },\n { key: 'atendeai.greeting_message', type: 'string', label: tl('Greeting', 'Mensagem de boas-vindas') },\n { key: 'atendeai.farewell_message', type: 'string', label: tl('Farewell', 'Mensagem de despedida') },\n { key: 'atendeai.handoff_message', type: 'string', label: tl('When handing over to a person', 'Ao passar para uma pessoa') },\n { key: 'atendeai.out_of_scope_message', type: 'string', label: tl('When the question is out of scope', 'Quando a pergunta foge do escopo') },\n ] },\n { title: tl('Limits', 'Limites'), fields: [\n { key: 'atendeai.max_messages_per_conversation', type: 'number', min: 1, max: 200, label: tl('Max AI messages per conversation', 'Máximo de mensagens da IA por conversa') },\n { key: 'atendeai.escalation_timeout_minutes', type: 'number', min: 1, max: 1440, label: tl('Minutes before handing over', 'Minutos até passar para uma pessoa') },\n ] },\n ],\n }),\n]\n","// ---------------------------------------------------------------------------\n// Campanhas, do lado do navegador.\n//\n// A leitura é direta (RLS por inquilino); o DISPARO passa pela função de borda,\n// porque é lá que a credencial mora e é lá que o ritmo é respeitado. O navegador\n// nunca fala com o Tyxter nem com o Evolution.\n// ---------------------------------------------------------------------------\nimport { getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core'\nimport type { ProviderId } from './providers'\n\nexport interface CampaignTemplate {\n id: string\n name: string\n language: string\n category: string\n body: string\n /** Os nomes das variáveis, na ordem de {{1}}, {{2}}. A Meta entende posição;\n * gente entende nome — e a tela pede \"cargo\", não \"variável 3\". */\n variables: string[]\n provider: string | null\n status: string\n statusDetail: string | null\n}\n\nexport interface CampaignProgress {\n campaignId: string\n name: string\n status: 'draft' | 'scheduled' | 'running' | 'paused' | 'done' | 'cancelled'\n pausedReason: string | null\n provider: string | null\n total: number\n queued: number\n sending: number\n sent: number\n delivered: number\n read: number\n replied: number\n failed: number\n skipped: number\n /** Abaixo de 30% a prática diz que o risco de banimento sobe. Fica na tela. */\n replyRate: number | null\n firstSentAt: string | null\n lastSentAt: string | null\n}\n\nexport interface DispatchResult {\n campaignId: string\n provider?: ProviderId\n sent: number\n remaining: number | null\n failures?: Array<{ to: string; code: string; message: string }>\n paused?: string\n skipped?: boolean\n reason?: string\n}\n\nfunction client() {\n const c = getSupabaseClientOptional() as any\n if (!c) throw new Error('Supabase não inicializado')\n return c\n}\n\nfunction tenant(): string {\n const t = getActiveTenantId()\n if (!t) throw new Error('Nenhuma casa ativa')\n return t\n}\n\nexport const campaignsApi = {\n async templates(): Promise<CampaignTemplate[]> {\n const { data, error } = await client()\n .from('plg_conversations_templates')\n .select('id, name, language, category, body, variables, provider, status, status_detail')\n .eq('tenant_id', tenant()).order('name')\n if (error) throw new Error(error.message)\n return ((data ?? []) as any[]).map((r) => ({\n id: r.id, name: r.name, language: r.language, category: r.category,\n body: r.body, variables: r.variables ?? [], provider: r.provider,\n status: r.status, statusDetail: r.status_detail ?? null,\n }))\n },\n\n async saveTemplate(t: { id?: string; name: string; body: string; variables?: string[]; language?: string; category?: string }) {\n const row = {\n tenant_id: tenant(), name: t.name, body: t.body,\n variables: t.variables ?? [], language: t.language ?? 'pt_BR',\n category: t.category ?? 'MARKETING', updated_at: new Date().toISOString(),\n }\n const q = t.id\n ? client().from('plg_conversations_templates').update(row).eq('id', t.id)\n : client().from('plg_conversations_templates').insert(row)\n const { error } = await q\n if (error) throw new Error(error.message)\n },\n\n async list(): Promise<CampaignProgress[]> {\n const { data, error } = await client()\n .from('v_conversations_campaign_progress')\n .select('*').eq('tenant_id', tenant())\n if (error) throw new Error(error.message)\n return ((data ?? []) as any[]).map((r) => ({\n campaignId: r.campaign_id, name: r.name, status: r.status,\n pausedReason: r.paused_reason ?? null, provider: r.provider,\n total: Number(r.total ?? 0), queued: Number(r.queued ?? 0),\n sending: Number(r.sending ?? 0), sent: Number(r.sent ?? 0),\n delivered: Number(r.delivered ?? 0), read: Number(r.read ?? 0),\n replied: Number(r.replied ?? 0), failed: Number(r.failed ?? 0),\n skipped: Number(r.skipped ?? 0),\n replyRate: r.reply_rate == null ? null : Number(r.reply_rate),\n firstSentAt: r.first_sent_at ?? null, lastSentAt: r.last_sent_at ?? null,\n }))\n },\n\n /** Cria a campanha e enfileira os destinatários.\n *\n * `ON CONFLICT DO NOTHING` via upsert: o índice único (campanha, telefone,\n * rodada) é quem impede o disparo duplo, e não uma checagem aqui. Dois\n * cliques no botão enfileiram uma vez. */\n async create(input: {\n name: string\n templateId?: string\n provider?: ProviderId\n channelId?: string\n targets: Array<{ phone: string; personId?: string; variables?: Record<string, string> | string[] }>\n }): Promise<string> {\n const tenantId = tenant()\n const { data: camp, error } = await client()\n .from('plg_conversations_campaigns')\n .insert({\n tenant_id: tenantId, name: input.name,\n template_id: input.templateId ?? null,\n provider: input.provider ?? null,\n channel_id: input.channelId ?? null,\n status: 'draft',\n })\n .select('id').single()\n if (error) throw new Error(error.message)\n\n const rows = input.targets\n .map((t) => ({\n tenant_id: tenantId, campaign_id: camp.id,\n phone_e164: String(t.phone).replace(/\\D/g, ''),\n person_id: t.personId ?? null,\n variables: t.variables ?? {},\n }))\n .filter((r) => r.phone_e164.length >= 10)\n\n // Em blocos: o PostgREST tem teto por requisição, e uma lista de 300 leads\n // numa inserção só volta truncada sem dizer que truncou.\n for (let i = 0; i < rows.length; i += 200) {\n const { error: e } = await client()\n .from('plg_conversations_campaign_targets')\n .upsert(rows.slice(i, i + 200), { onConflict: 'campaign_id,phone_e164,rotation', ignoreDuplicates: true })\n if (e) throw new Error(e.message)\n }\n return camp.id as string\n },\n\n async setStatus(campaignId: string, status: CampaignProgress['status']) {\n const patch: Record<string, unknown> = { status, updated_at: new Date().toISOString() }\n if (status === 'running') { patch.started_at = new Date().toISOString(); patch.paused_reason = null }\n const { error } = await client()\n .from('plg_conversations_campaigns').update(patch).eq('id', campaignId)\n if (error) throw new Error(error.message)\n },\n\n /** Um lote. Quem chama repete até `remaining` chegar a zero — o arrendamento\n * de cinco minutos é o que impede duas chamadas de mandarem o mesmo. */\n async dispatch(campaignId: string, limit?: number): Promise<DispatchResult> {\n const { data, error } = await client().functions.invoke('conversations-provider', {\n body: { tenantId: tenant(), action: 'dispatch', campaignId, limit },\n })\n if (error) {\n const detail = (await error.context?.json?.().catch(() => null)) as { message?: string } | null\n throw new Error(detail?.message ?? error.message)\n }\n if ((data as any)?.error) throw new Error((data as any).message ?? (data as any).error)\n return data as DispatchResult\n },\n}\n","import React from 'react'\nimport { evolutionConnectorDef } from './integrations/evolution/connectorDef'\nimport { InboxWatcher } from './components/InboxWatcher'\nimport type { EntityDef, PluginManifest, PluginScope, VerticalId } from '@fayz-ai/core'\nimport { lazyComponent, getActiveTenantId, getSupabaseClientOptional, registerTranslations } from '@fayz-ai/core'\nimport type { EntityLookup } from '@fayz-ai/admin'\nimport type { ResolvedConversationsConfig } from './context'\nimport type { ConversationsProvider } from './data/types'\nimport { createMockConversationsProvider } from './data/mock'\nimport { createSupabaseConversationsProvider } from './data/supabase'\nimport { createConversationsStore } from './store'\nimport { conversationsLocales } from './locales'\nimport { createConversationsDashboardWidgets } from './views/dashboardWidgets'\nimport { buildConversationsOnboarding } from './lib/onboarding'\nimport { tyxterConnectorDef } from './integrations/tyxter/connectorDef'\nimport { MIGRATIONS } from './migrations'\n\n// ---------------------------------------------------------------------------\n// @fayz-ai/plugin-conversations — the GoHighLevel \"Conversations\" equivalent:\n// one omni-channel inbox (SMS / WhatsApp / Instagram / Email / Web chat).\n// Universal plugin — reusable by any vertical (beauty, resto, agency…).\n//\n// Supabase-backed (plg_conversations / plg_conversation_messages, tenant-scoped\n// via RLS) when a client is registered; a persisted mock inbox otherwise.\n// WhatsApp arrives through the Tyxter connector declared below; the other\n// channels still deliver inbound rows out-of-band, and this plugin stays the\n// read/compose surface for all of them.\n// ---------------------------------------------------------------------------\n\nexport interface ConversationsPluginOptions {\n navPosition?: number\n navSection?: 'main' | 'secondary' | 'settings'\n navLabel?: string\n scope?: PluginScope\n verticalId?: VerticalId\n dataProvider?: ConversationsProvider\n\n /**\n * `people.kind` for contacts created from the compose modal's picker. Each\n * vertical names its people differently (beauty 'client', agency 'lead'),\n * hence a knob rather than a hardcoded value. Default: 'contact'.\n */\n contactKind?: string\n /** Custom search source for the picker. Defaults to the person archetype lookup. */\n contactLookup?: EntityLookup\n /**\n * The app's contact entity, same definition its registry page uses. \"Create\"\n * in the picker opens THAT form. Without it the picker searches only.\n */\n contactEntityDef?: EntityDef\n}\n\nfunction createSafeProvider(): ConversationsProvider {\n // Real data when a Supabase client is registered; mock inbox otherwise.\n // Resolution is LAZY (per call): createConversationsPlugin runs at module\n // scope in the app config, BEFORE the Supabase client is registered — an\n // eager check here would capture the mock forever even on live backends.\n let real: ConversationsProvider | null = null\n let mock: ConversationsProvider | null = null\n const resolve = (): ConversationsProvider => {\n if (getSupabaseClientOptional()) {\n real ??= createSupabaseConversationsProvider({ tenantId: () => getActiveTenantId() })\n return real\n }\n mock ??= createMockConversationsProvider({ tenantId: () => getActiveTenantId() })\n return mock\n }\n return {\n listConversations: (...a) => resolve().listConversations(...a),\n getMessages: (...a) => resolve().getMessages(...a),\n sendMessage: (...a) => resolve().sendMessage(...a),\n markRead: (...a) => resolve().markRead(...a),\n setStatus: (...a) => resolve().setStatus(...a),\n createConversation: (...a) => resolve().createConversation(...a),\n }\n}\n\nexport function createConversationsPlugin(options?: ConversationsPluginOptions): PluginManifest {\n registerTranslations(conversationsLocales)\n const provider = options?.dataProvider ?? createSafeProvider()\n const store = createConversationsStore(provider)\n\n const config: ResolvedConversationsConfig = {\n contactKind: options?.contactKind ?? 'contact',\n contactLookup: options?.contactLookup,\n contactEntityDef: options?.contactEntityDef,\n }\n\n const dashboardWidgets = createConversationsDashboardWidgets({ store, config })\n\n const PageComponent: React.ComponentType<unknown> = () =>\n React.createElement(ConversationsPage, { store, config })\n PageComponent.displayName = 'ConversationsPage'\n\n return {\n id: 'conversations',\n defaultAgentRole: 'frontdesk',\n name: options?.navLabel ?? 'Conversations',\n icon: 'MessageCircle',\n version: '1.0.0',\n scope: options?.scope ?? 'universal',\n verticalId: options?.verticalId,\n defaultEnabled: true,\n dependencies: [],\n declaredFeatures: [{ id: 'conversations', label: 'Conversations', group: 'Engage' }],\n // Recurring monthly quota — counts conversation threads created this month.\n declaredLimits: [\n { key: 'conversations_month', label: 'Conversations this month', table: 'plg_conversations', period: 'month' },\n ],\n // `/conversations` has its rail line and its own screen. From 09-28 the\n // inbox lived as a header icon and from 10-15 in the right column beside\n // the assistant; the column squeezed the thread into a sliver and lost\n // what the full screen does. The unread count is written on this line by\n // the watcher below.\n //\n // E SEM CAMPANHAS NEM TEMPLATES. As duas telas foram removidas — não\n // escondidas: elas tomavam duas linhas de rail num plugin que declara, na\n // nota acima, que nem a própria caixa de entrada merece uma. Ficavam\n // acima de Encontros, CRM e Financeiro em toda conta com conversas\n // ligadas, e a segunda cópia que apareceu embaixo de Estoque foi o sinal\n // de que ninguém sabia mais de onde elas vinham.\n //\n // O MAQUINÁRIO FICA: `campaignsApi`, `plg_conversations_campaigns` e o\n // ritmo de disparo continuam, e é por eles que Marketing e Automações\n // mandam mensagem. O que saiu foi a tela solta e o link para ela.\n // AtendeAI does get a rail line, as in V1: whoever runs the AI follows it\n // all day. Offered to every account — off, the page is the upsell.\n navigation: [\n {\n id: 'conversations',\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 1,\n label: options?.navLabel ?? 'Conversations',\n route: '/conversations',\n icon: 'MessageCircle',\n permission: { feature: 'conversations', action: 'read' as const },\n },\n // AtendeAI é recurso de restaurante (ChefControl): só aparece no vertical\n // 'food'. Uma loja de outro ramo não vê a linha.\n { section: 'main', position: 45, label: 'AtendeAI', route: '/atendeai', icon: 'Bot', before: ['/analytics', '/reports'], verticalId: 'food' as const, permission: { feature: 'conversations', action: 'read' as const } },\n ],\n routes: [\n {\n path: '/atendeai',\n component: AtendeAIPage as unknown as React.ComponentType<unknown>,\n permission: { feature: 'conversations', action: 'read' as const },\n },\n {\n path: '/conversations',\n component: PageComponent,\n fullBleed: true,\n permission: { feature: 'conversations', action: 'read' as const },\n },\n ],\n // The watcher renders nothing; it is a header control because header\n // controls live outside the route switch, so the chime, the system\n // notification and the rail badge survive navigation.\n headerControls: [{\n id: 'conversations-inbox',\n component: (() => {\n const W: React.FC = () => React.createElement(InboxWatcher, {\n label: options?.navLabel ?? 'Conversations',\n section: options?.navSection ?? 'main',\n position: options?.navPosition ?? 1,\n })\n W.displayName = 'InboxWatcher'\n return W as unknown as React.ComponentType<unknown>\n })(),\n order: 95,\n }],\n dashboardWidgets,\n events: [\n { name: 'conversations.message.received', description: 'An inbound message arrived on any channel' },\n { name: 'conversations.message.sent', description: 'An outbound message was sent' },\n {\n // Emitted server-side by plg_emit_event, from the tyxter-webhook's\n // payment handler — the browser never sees this write, which is the\n // whole reason packages/db/migrations/027 exists.\n name: 'conversations.payment_received',\n title: 'Pagamento recebido na conversa',\n description: 'O cliente pagou uma cobrança enviada dentro da conversa',\n trigger: 'Quando o provedor confirma o pagamento de uma cobrança aberta no chat',\n icon: 'BadgeDollarSign',\n fields: [\n { name: 'amount', label: 'Valor', type: 'money', example: 'R$ 120,00' },\n { name: 'amount_cents', label: 'Valor em centavos', type: 'number', example: '12000' },\n { name: 'currency', label: 'Moeda', type: 'string', example: 'BRL' },\n { name: 'description', label: 'Descrição da cobrança', type: 'string', example: 'Corte + Escova' },\n { name: 'channel', label: 'Canal', type: 'string', example: 'whatsapp' },\n { name: 'provider', label: 'Provedor', type: 'string', example: 'tyxter' },\n // The subject is the BOOKING, not the charge: an automation reacting\n // to this needs the thing that was paid for, and the charge id is the\n // audit trail beside it.\n { name: 'subject_type', label: 'Tipo do registro', type: 'string', example: 'booking' },\n { name: 'subject_id', label: 'Registro', type: 'id', example: '9f1c…' },\n { name: 'payment_request_id', label: 'Cobrança', type: 'id', example: '3ab2…' },\n ],\n },\n ],\n aiTools: [\n {\n id: 'conversations.list-threads',\n name: 'listConversations',\n description: 'Lists open conversations across all channels, optionally filtered by channel.',\n icon: 'MessageCircle',\n mode: 'read' as const,\n category: 'Conversations',\n parameters: {\n type: 'object' as const,\n properties: {\n channel: {\n type: 'string' as const,\n enum: ['all', 'sms', 'whatsapp', 'instagram', 'email', 'webchat'],\n },\n },\n },\n suggestions: [\n { label: 'Mostre as conversas não lidas' },\n { label: 'Chegou mensagem nova no WhatsApp?' },\n ],\n permission: { feature: 'conversations', action: 'read' as const },\n },\n {\n id: 'conversations.send-message',\n name: 'sendMessage',\n description: 'Sends a reply in a conversation thread.',\n icon: 'Send',\n mode: 'persist' as const,\n category: 'Conversations',\n parameters: {\n type: 'object' as const,\n properties: {\n conversationId: { type: 'string' as const, description: 'Conversation id' },\n body: { type: 'string' as const, description: 'Message body' },\n },\n required: ['conversationId', 'body'],\n },\n permission: { feature: 'conversations', action: 'create' as const },\n },\n ],\n // One baseline per unit since #338 — read from the generated barrel\n // rather than listed here, so regenerating the SQL never needs a\n // manifest edit to match.\n migrations: MIGRATIONS.map((entry) => ({\n id: `conversations-${entry.id}`,\n version: '1.0.0',\n sql: entry.sql,\n description:\n 'The whole schema this plugin provisions, as one file: every table, view, function, policy and grant, plus the reference rows it seeds. Replaced the per-change chain in the 1.0.0 squash (#338); the files it collapsed are kept, unapplied, in src/migrations.archive/.',\n })),\n functions: [\n {\n slug: 'tyxter-webhook',\n // PUBLIC, and the only function in this plugin that is. The caller is\n // Tyxter's infrastructure, which has no Supabase session and never\n // will — so the gateway check is off and the HMAC signature over\n // `${timestamp}.${rawBody}` IS the authentication.\n ingress: 'none',\n verifyJwt: false,\n // NAMES only. TYXTER_WEBHOOK_SECRET is the endpoint signing secret,\n // returned exactly ONCE by POST /v1/webhook-endpoints and stored as a\n // pool secret by the provisioning script — it is per-endpoint, which is\n // why it can live in the pool while the API key cannot.\n secrets: [\n 'TYXTER_WEBHOOK_SECRET',\n 'TYXTER_API_BASE_URL',\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n ],\n },\n {\n slug: 'tyxter-template-sync',\n // Two callers, neither of them the outside world: an operator with a\n // Supabase JWT, and an ops script with TYXTER_SYNC_SECRET. The second\n // cannot present a JWT, so the gateway check has to be off and the\n // function authenticates itself.\n ingress: 'none',\n verifyJwt: false,\n // NAMES only. The Tyxter key is NOT here and could not be: a Supabase\n // secret is per-POOL and the key belongs to the platform's project — it\n // is redeemed per run from the vault, which is what the last three are for.\n secrets: [\n 'TYXTER_API_BASE_URL',\n 'TYXTER_SYNC_SECRET',\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n ],\n },\n {\n slug: 'tyxter-payment-preflight',\n // verify_jwt TRUE — the only function in this wave with a human caller\n // and nothing else. An operator looking at the connector panel has a\n // Supabase session; there is no clock and no ops script here, so the\n // gateway's own check is left on and membership is checked on top of it.\n ingress: 'none',\n verifyJwt: true,\n // NAMES only. The browser cannot ask Tyxter anything — the key is the\n // platform's — which is the whole reason this function exists.\n secrets: [\n 'TYXTER_API_BASE_URL',\n 'FAYZ_API_URL',\n 'FAYZ_PROJECT_ID',\n 'CONNECTOR_REDEMPTION_SECRET',\n ],\n },\n ],\n // The settings screen exists so the connector below can be REACHED: the\n // Integrations tab is drawn by PluginSettingsPanel, so a plugin with a\n // connector and no settings route ships a connector nobody can open.\n facets: [\n { id: 'atendeai', label: 'AtendeAI', description: 'A inteligência artificial que responde no WhatsApp.' },\n ],\n settings: [\n ...conversationsV1SettingsTabs,\n {\n id: 'conversations',\n label: 'Conversas',\n icon: 'MessageCircle',\n component: ConversationsSettingsTab as React.ComponentType<unknown>,\n order: 30,\n permission: { feature: 'conversations', action: 'read' as const },\n },\n ],\n onboarding: { program: buildConversationsOnboarding() },\n // WhatsApp through Tyxter or through the store's own number (Evolution).\n // Declared here because this plugin IS the inbox the messages land in;\n // both show on Configurações → Conectores like every other connector.\n connectors: [tyxterConnectorDef, evolutionConnectorDef],\n locales: conversationsLocales,\n }\n}\n\nexport type { ConversationsProvider } from './data/types'\nexport type { Conversation, Message, Channel, MessageDirection, CreateConversationInput } from './types'\nexport { isWaitingOnUs } from './types'\nexport { createMockConversationsProvider, type MockConversationsConfig } from './data/mock'\nexport {\n createSupabaseConversationsProvider,\n type SupabaseConversationsConfig,\n} from './data/supabase'\n// The automations template editor gates its `pay` action on this, so it has to\n// leave the plugin — see PaymentReadiness for why `ready` alone is not the test.\nexport {\n readPaymentReadiness,\n openPaymentSetupSession,\n canOfferPayment,\n PAYMENT_PREFLIGHT_FUNCTION,\n type PaymentReadiness,\n type PaymentActiveMode,\n type PaymentSetupSession,\n} from './data/payment-preflight'\nexport {\n listMessagingChannels,\n type MessagingChannelAccount,\n type MessagingChannelKind,\n type MessagingChannelStatus,\n type ListMessagingChannelsOptions,\n} from './data/channels'\n// Exported so a bespoke admin can render the connector without mounting the\n// whole plugin — the same reason plugin-shop exports its definitions.\nexport {\n tyxterConnectorDef,\n TYXTER_CONNECTOR_ID,\n TYXTER_LATENCY_BUDGET_MS,\n} from './integrations/tyxter/connectorDef'\nimport { conversationsV1SettingsTabs } from './settings/v1-settings'\n\n// Code loads when it is first drawn, not with the app. Pages use React.lazy\n// (the shell's route boundary shows the page skeleton); anything that may\n// render elsewhere uses lazyComponent, which carries its own boundary.\nconst ConversationsPage = React.lazy(() => import('./views/ConversationsPage').then((m) => ({ default: m.ConversationsPage })))\nconst AtendeAIPage = React.lazy(() => import('./views/AtendeAIPage').then((m) => ({ default: m.AtendeAIPage })))\nconst ConversationsSettingsTab = lazyComponent(() => import('./settings/ConversationsSettings').then((m) => m.ConversationsSettingsTab))\n\n// A campanha e os provedores, exportados para que outro plugin possa criar uma\n// campanha sem montar a caixa de entrada inteira. É o que deixa a lista de\n// leads do CRM oferecer \"Enviar WhatsApp\" carregando este módulo sob demanda:\n// um import estático faria a lista quebrar num app onde este plugin não está.\nexport { campaignsApi } from './data/campaigns'\nexport type { CampaignProgress, CampaignTemplate, DispatchResult } from './data/campaigns'\nexport { providersApi } from './data/providers'\nexport type { ProviderId, ProviderRow, ProviderNumber, ProviderTemplate, ProviderCapabilities } from './data/providers'\nexport { WhatsAppProviders } from './settings/WhatsAppProviders'\n"]}
|