@adatechnology/conversations-ui 0.1.0-rc.3 → 0.1.0-rc.31

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.
Files changed (143) hide show
  1. package/dist/chunk-CUYYYZWD.js +2317 -0
  2. package/dist/chunk-DXPSPUWF.js +110 -0
  3. package/dist/{chunk-OGRRHQQW.js → chunk-WCBDXZ3X.js} +68 -4
  4. package/dist/flows/index.d.ts +338 -4
  5. package/dist/flows/index.js +1331 -55
  6. package/dist/index.d.ts +1074 -42
  7. package/dist/index.js +3572 -742
  8. package/dist/preview/index.d.ts +328 -8
  9. package/dist/preview/index.js +902 -115
  10. package/dist/styles.css +899 -0
  11. package/dist/types-De5aN-E_.d.ts +502 -0
  12. package/package.json +3 -3
  13. package/src/AudioPlayer.tsx +8 -0
  14. package/src/AudioRecorderButton.test.tsx +30 -0
  15. package/src/AudioRecorderButton.tsx +248 -0
  16. package/src/AudioTranscription.test.tsx +115 -0
  17. package/src/AudioTranscription.tsx +252 -0
  18. package/src/Avatar.tsx +14 -3
  19. package/src/ConversationContextPanel.tsx +218 -44
  20. package/src/ConversationDocumentsPanel.tsx +347 -24
  21. package/src/ConversationHeader.test.tsx +66 -0
  22. package/src/ConversationHeader.tsx +163 -45
  23. package/src/ConversationListItem.tsx +19 -2
  24. package/src/ConversationLocalesProvider.tsx +42 -0
  25. package/src/ConversationRow.tsx +31 -7
  26. package/src/DocumentsLibrary.tsx +382 -0
  27. package/src/EmojiPicker.tsx +70 -55
  28. package/src/FileIcon.test.ts +83 -0
  29. package/src/FileIcon.tsx +88 -11
  30. package/src/InteractiveMessage.test.tsx +41 -0
  31. package/src/InteractiveMessage.tsx +146 -0
  32. package/src/Lightbox.tsx +18 -3
  33. package/src/MediaRenderer.tsx +98 -22
  34. package/src/MessageBubble.test.tsx +41 -0
  35. package/src/MessageBubble.tsx +75 -6
  36. package/src/MessageComposer.test.tsx +35 -0
  37. package/src/MessageComposer.tsx +155 -19
  38. package/src/RichMessageComposer.test.tsx +113 -0
  39. package/src/RichMessageComposer.tsx +551 -0
  40. package/src/SimpleEmojiPicker.tsx +5 -3
  41. package/src/StatusTicks.tsx +1 -1
  42. package/src/Toast.tsx +4 -0
  43. package/src/Tooltip.test.ts +42 -0
  44. package/src/Tooltip.tsx +164 -0
  45. package/src/Wallpaper.test.tsx +21 -0
  46. package/src/Wallpaper.tsx +67 -7
  47. package/src/WhatsAppMessageEditor.tsx +28 -4
  48. package/src/WindowExpiredNotice.tsx +12 -4
  49. package/src/audioRecorderFormat.test.ts +67 -0
  50. package/src/buildOutput.test.ts +79 -0
  51. package/src/composer.constant.ts +33 -0
  52. package/src/conversationTranscript.test.ts +57 -0
  53. package/src/conversationTranscript.ts +29 -4
  54. package/src/conversationWindow.ts +7 -5
  55. package/src/documentTypeLabel.test.ts +57 -0
  56. package/src/documents/DocumentsWorkspace.tsx +550 -0
  57. package/src/documents/index.ts +8 -0
  58. package/src/documents/labels.ts +92 -0
  59. package/src/emojiCatalog.test.ts +35 -0
  60. package/src/emojiCatalog.ts +189 -0
  61. package/src/flows/FlowGroupHeader.tsx +12 -2
  62. package/src/flows/FlowMapCanvas.tsx +15 -12
  63. package/src/flows/FlowMapNode.tsx +4 -1
  64. package/src/flows/FlowNodeCard.tsx +35 -8
  65. package/src/flows/FlowNodePanel.tsx +149 -38
  66. package/src/flows/FlowPalette.tsx +13 -3
  67. package/src/flows/FlowPortalNode.tsx +1 -1
  68. package/src/flows/FlowWhatsAppPreview.tsx +14 -3
  69. package/src/flows/FlowsWorkspace.tsx +1023 -0
  70. package/src/flows/flowCanvasModel.test.ts +312 -0
  71. package/src/flows/flowCanvasModel.ts +368 -0
  72. package/src/flows/flowEditorOps.test.ts +241 -0
  73. package/src/flows/flowEditorOps.ts +177 -0
  74. package/src/flows/flowGraph.ts +6 -6
  75. package/src/flows/index.ts +47 -1
  76. package/src/flows/labels.ts +141 -0
  77. package/src/flows/workspaceContract.test.ts +95 -0
  78. package/src/hooks/useContainerWidth.ts +35 -0
  79. package/src/hooks/useConversationActions.ts +56 -0
  80. package/src/hooks/useConversationDocuments.ts +11 -7
  81. package/src/hooks/useConversationList.ts +15 -9
  82. package/src/hooks/useConversationMessages.ts +2 -2
  83. package/src/hooks/useConversationRealtime.ts +10 -8
  84. package/src/hooks/useScrollToLatestMessage.ts +127 -0
  85. package/src/hooks/useUrlFilterState.ts +107 -0
  86. package/src/icon.constant.ts +12 -0
  87. package/src/index.ts +114 -13
  88. package/src/lib/cn.test.ts +29 -0
  89. package/src/lib/composer-formatting.test.ts +78 -0
  90. package/src/lib/composer-formatting.ts +145 -0
  91. package/src/lib/createMediaUrlResolver.ts +33 -0
  92. package/src/lib/paginated.test.ts +33 -0
  93. package/src/lib/paginated.ts +26 -0
  94. package/src/lib/whatsapp-formatting.test.tsx +37 -0
  95. package/src/lib/whatsapp-formatting.tsx +28 -3
  96. package/src/listing/index.tsx +202 -0
  97. package/src/pagination.constant.ts +10 -0
  98. package/src/preview/ConversationPreview.tsx +199 -13
  99. package/src/preview/ConversationSimulatorPanel.test.tsx +55 -0
  100. package/src/preview/ConversationSimulatorPanel.tsx +89 -0
  101. package/src/preview/MediaTypesPreview.tsx +87 -0
  102. package/src/preview/conversationPreviewFailures.test.ts +64 -0
  103. package/src/preview/createMockConversationsApi.ts +175 -15
  104. package/src/preview/createPreviewBridgeClient.test.ts +92 -0
  105. package/src/preview/createPreviewBridgeClient.ts +124 -0
  106. package/src/preview/createPreviewMediaUploader.ts +82 -0
  107. package/src/preview/createPreviewWebhookClient.test.ts +96 -0
  108. package/src/preview/createPreviewWebhookClient.ts +127 -4
  109. package/src/preview/index.ts +33 -3
  110. package/src/preview/mediaTypeOf.test.ts +15 -0
  111. package/src/preview/mockDocumentsSearch.test.ts +57 -0
  112. package/src/preview/preview.test.ts +5 -3
  113. package/src/preview/previewFileSamples.test.ts +151 -0
  114. package/src/preview/previewFileSamples.ts +74 -0
  115. package/src/preview/previewFixtures.ts +288 -1
  116. package/src/preview/previewMediaSource.test.ts +62 -0
  117. package/src/preview/previewMediaSource.ts +91 -0
  118. package/src/preview/previewMediaUploader.test.ts +61 -0
  119. package/src/providers/ConversationsProvider.tsx +8 -6
  120. package/src/providers/types.ts +185 -10
  121. package/src/quickReply.test.ts +58 -0
  122. package/src/settings/MessagesWorkspace.tsx +468 -0
  123. package/src/settings/TopicsForm.tsx +2 -0
  124. package/src/settings/TranscriptionSettingsForm.test.tsx +81 -0
  125. package/src/settings/TranscriptionSettingsForm.tsx +190 -0
  126. package/src/settings/WelcomeFarewellForm.tsx +1 -0
  127. package/src/settings/WhatsAppCreateTemplateForm.tsx +4 -1
  128. package/src/settings/WhatsAppTemplateSettingsForm.tsx +5 -2
  129. package/src/settings/WhatsAppTemplatesSettings.tsx +9 -1
  130. package/src/styles.css +862 -0
  131. package/src/types.ts +64 -1
  132. package/src/useWaitingNotifications.ts +74 -29
  133. package/src/workspace/BulkTemplateModal.tsx +132 -0
  134. package/src/workspace/ConversationPane.tsx +432 -0
  135. package/src/workspace/ConversationsInboxList.tsx +194 -0
  136. package/src/workspace/ConversationsWorkspace.tsx +346 -0
  137. package/src/workspace/index.ts +12 -0
  138. package/src/workspace/labels.test.ts +17 -0
  139. package/src/workspace/labels.ts +85 -0
  140. package/src/workspace/useConversationsInbox.ts +332 -0
  141. package/dist/chunk-N7B24WYD.js +0 -719
  142. package/dist/chunk-NV2RZ5KT.js +0 -56
  143. package/dist/types-C0PtaO7S.d.ts +0 -207
package/dist/index.d.ts CHANGED
@@ -1,15 +1,7 @@
1
1
  import * as react from 'react';
2
- import react__default, { ReactNode, FormEvent } from 'react';
3
- import { M as MessagePayload, k as ConversationsFeatures, i as ConversationSummary, f as ConversationChannel, j as ConversationsApi, S as SSEProvider, g as ConversationDocument } from './types-C0PtaO7S.js';
4
- export { C as CHANNEL_CAPABILITIES, a as CHANNEL_FILTER_ALL, b as CONVERSATION_CHANNEL, c as ChannelCapabilities, d as ChannelFilter, e as ChannelFilterOption, h as ConversationEventSource, l as ConversationsTheme, m as ConversationsUIConfig, D as DEFAULT_CONVERSATION_CHANNEL, F as FormatContactHandleParams, H as HANDLE_KIND, n as HandleKind, R as REOPEN_MECHANISM, o as ReopenMechanism, p as capabilitiesOf, q as channelFiltersFor, r as contactFlag, s as formatContactHandle } from './types-C0PtaO7S.js';
5
-
6
- type ResolveMediaUrl = (message: MessagePayload) => Promise<string | null>;
7
- interface MediaRendererProps {
8
- message: MessagePayload;
9
- onLightbox: (src: string) => void;
10
- onResolveUrl?: ResolveMediaUrl;
11
- }
12
- declare function MediaRenderer({ message, onLightbox, onResolveUrl }: MediaRendererProps): react.JSX.Element | null;
2
+ import react__default, { ReactNode, CSSProperties, UIEvent, FormEvent, RefObject } from 'react';
3
+ import { G as MessagePayload, N as ResolveMediaUrl, z as InteractiveSelection, J as MessageTranscription, x as InteractivePayload, r as ConversationsFeatures, o as ConversationSummary, j as ConversationChannel, L as ListConversationsParams, q as ConversationsApi, S as SSEProvider, T as TranscriptionMode, B as ListDocumentsParams, k as ConversationDocument, p as ConversationTemplate, f as ChannelFilter, g as ChannelFilterOption } from './types-De5aN-E_.js';
4
+ export { A as AudioRecorderButton, a as AudioRecorderButtonLabels, b as AudioRecorderButtonProps, C as CHANNEL_CAPABILITIES, c as CHANNEL_FILTER_ALL, d as CONVERSATION_CHANNEL, e as ChannelCapabilities, h as CompanyDocument, i as CompanyDocumentPage, l as ConversationDocumentPage, m as ConversationEventSource, n as ConversationPage, s as ConversationsTheme, t as ConversationsUIConfig, D as DEFAULT_AUDIO_RECORDER_BUTTON_LABELS, u as DEFAULT_CONVERSATION_CHANNEL, v as DEFAULT_MAX_RECORDING_MILLISECONDS, F as FormatContactHandleParams, H as HANDLE_KIND, w as HandleKind, I as InteractiveOption, y as InteractiveSection, M as MediaRenderer, E as MediaRendererProps, R as REOPEN_MECHANISM, K as ReopenMechanism, O as TranscriptionStatus, P as capabilitiesOf, Q as channelFiltersFor, U as contactFlag, V as formatContactHandle } from './types-De5aN-E_.js';
13
5
 
14
6
  interface MessageBubbleProps {
15
7
  message: MessagePayload;
@@ -19,16 +11,56 @@ interface MessageBubbleProps {
19
11
  isSelecting?: boolean;
20
12
  isSelected?: boolean;
21
13
  onToggleSelect?: () => void;
14
+ /**
15
+ * Como buscar a mídia da mensagem. Ausente, o balão usa o `ConversationsApi` do
16
+ * `ConversationsProvider` — passe apenas para sobrescrever (cache próprio, CDN, proxy do host).
17
+ */
22
18
  onResolveMediaUrl?: ResolveMediaUrl;
19
+ /**
20
+ * Toque numa opção do menu interativo. Ausente, as opções aparecem desabilitadas — que é o certo
21
+ * no histórico da inbox: o operador vê o que foi oferecido, sem responder no lugar do cliente.
22
+ */
23
+ onInteractiveSelect?: (selection: InteractiveSelection) => void;
24
+ /**
25
+ * Pede a transcrição do áudio. Ausente, o balão usa `transcribeAudio` do `ConversationsApi` do
26
+ * contexto — passe apenas para sobrescrever. Sem nenhum dos dois, o bloco de transcrição só exibe
27
+ * o que já veio pronto do backend.
28
+ */
29
+ onTranscribeAudio?: (messageId: string) => Promise<MessageTranscription | void>;
30
+ className?: string;
31
+ }
32
+ declare function MessageBubble({ message, isMine, senderName, isFirstInGroup, isSelecting, isSelected, onToggleSelect, onResolveMediaUrl, onInteractiveSelect, onTranscribeAudio, className, }: MessageBubbleProps): react.JSX.Element;
33
+
34
+ interface InteractiveMessageLabels {
35
+ /** Fallback do rótulo do botão que abre a lista, quando o payload não traz um. */
36
+ openList: string;
37
+ }
38
+ declare const DEFAULT_INTERACTIVE_MESSAGE_LABELS: InteractiveMessageLabels;
39
+ interface InteractiveMessageProps {
40
+ payload: InteractivePayload;
41
+ onSelect?: (selection: InteractiveSelection) => void;
42
+ labels?: Partial<InteractiveMessageLabels>;
23
43
  className?: string;
24
44
  }
25
- declare function MessageBubble({ message, isMine, senderName, isFirstInGroup, isSelecting, isSelected, onToggleSelect, onResolveMediaUrl, className, }: MessageBubbleProps): react.JSX.Element;
45
+ declare function InteractiveMessage({ payload, onSelect, labels, className }: InteractiveMessageProps): react.JSX.Element;
26
46
 
27
47
  interface ConversationWallpaperProps {
28
48
  children?: ReactNode;
29
49
  className?: string;
50
+ /** Ajusta ou substitui o fundo padrão — para produto com identidade visual própria. */
51
+ style?: CSSProperties;
52
+ /**
53
+ * Rolagem da área de mensagens. Par do `ref`: é este elemento que rola, então é aqui que
54
+ * `useScrollToLatestMessage` observa a posição para saber se o operador está acompanhando o fim.
55
+ */
56
+ onScroll?: (event: UIEvent<HTMLDivElement>) => void;
30
57
  }
31
- declare function ConversationWallpaper({ children, className }: ConversationWallpaperProps): react.JSX.Element;
58
+ /**
59
+ * `forwardRef` porque quem controla a rolagem é de fora — o hook precisa do elemento para saltar
60
+ * até a última mensagem. `forwardRef` e não `ref` como prop: o pacote suporta React 18, onde
61
+ * ref-como-prop ainda não existe.
62
+ */
63
+ declare const ConversationWallpaper: react.ForwardRefExoticComponent<ConversationWallpaperProps & react.RefAttributes<HTMLDivElement>>;
32
64
 
33
65
  interface ConversationLocales {
34
66
  bubble: {
@@ -44,6 +76,27 @@ interface ConversationLocales {
44
76
  listenAudio: string;
45
77
  viewVideo: string;
46
78
  moderationFlagged: string;
79
+ mediaLoading: string;
80
+ mediaRetry: string;
81
+ mediaError: string;
82
+ mediaUnavailable: string;
83
+ imageAlt: string;
84
+ untitledDocument: string;
85
+ downloadFile: string;
86
+ };
87
+ transcription: {
88
+ label: string;
89
+ copy: string;
90
+ copied: string;
91
+ transcribe: string;
92
+ transcribing: string;
93
+ retry: string;
94
+ failed: string;
95
+ /** Áudio processado sem fala detectada — distinto de "não transcrito". */
96
+ empty: string;
97
+ unsupported: string;
98
+ showMore: string;
99
+ showLess: string;
47
100
  };
48
101
  selection: {
49
102
  select: string;
@@ -69,13 +122,97 @@ interface AudioPlayerProps {
69
122
  }
70
123
  declare function AudioPlayer({ src, isMine }: AudioPlayerProps): react.JSX.Element;
71
124
 
125
+ interface AudioTranscriptionProps {
126
+ transcription?: MessageTranscription | null;
127
+ /**
128
+ * Pede a transcrição ao backend. Ausente, o bloco nunca oferece o botão — um host em modo
129
+ * automático não tem rota para isso, e desenhar um botão que estoura no clique é pior do que não
130
+ * desenhar nada.
131
+ *
132
+ * O que for devolvido é exibido na hora. Sem isso o texto só apareceria no próximo refetch da
133
+ * lista, e transcrição não emite evento de tempo real: o operador clicaria, veria o spinner
134
+ * terminar e continuaria sem o texto na tela.
135
+ */
136
+ onTranscribe?: () => Promise<MessageTranscription | void>;
137
+ isMine?: boolean;
138
+ }
139
+ /**
140
+ * Transcrição sob a nota de voz, com botão de copiar.
141
+ *
142
+ * Copiar é o motivo de o bloco existir: o operador cola o pedido do cliente no sistema interno, no
143
+ * orçamento, na busca. Seleção manual de texto dentro de um balão de chat é exatamente onde o
144
+ * arrasto do mouse falha — pega o balão vizinho, o horário, o nome do remetente.
145
+ *
146
+ * `navigator.clipboard.writeText` com try/catch silencioso, mesmo padrão de `MessageText.tsx`: a API
147
+ * exige contexto seguro e permissão, e um host servindo em HTTP simples não a tem. Falhar sem alarme
148
+ * é o certo — o texto continua na tela para seleção manual.
149
+ */
150
+ declare function AudioTranscription({ transcription, onTranscribe, isMine }: AudioTranscriptionProps): react.JSX.Element | null;
151
+
152
+ interface EmojiPickerLabels {
153
+ search: string;
154
+ noResults: string;
155
+ }
156
+ declare const DEFAULT_EMOJI_PICKER_LABELS: EmojiPickerLabels;
72
157
  interface EmojiPickerProps {
73
158
  onSelect: (emoji: string) => void;
159
+ labels?: Partial<EmojiPickerLabels>;
74
160
  className?: string;
75
161
  }
76
- declare const EmojiPicker: ({ onSelect, className }: EmojiPickerProps) => react.JSX.Element;
162
+ declare const EmojiPicker: ({ onSelect, labels, className }: EmojiPickerProps) => react.JSX.Element;
77
163
 
164
+ /**
165
+ * Catálogo de emojis com palavras-chave em português, usado pela busca do seletor.
166
+ *
167
+ * Fica em módulo próprio (e não dentro do `EmojiPicker`) porque a busca precisa varrer TODAS as
168
+ * categorias, não só a aberta — o índice é montado uma vez, no carregamento, e não a cada tecla.
169
+ *
170
+ * As palavras-chave são de busca, não legendas: incluem sinônimos e formas sem acento, porque quem
171
+ * digita rápido escreve "coracao" e "polegar" com a mesma frequência que a forma correta.
172
+ */
173
+ type EmojiEntry = {
174
+ readonly emoji: string;
175
+ readonly keywords: readonly string[];
176
+ };
177
+ type EmojiCategory = {
178
+ readonly name: string;
179
+ readonly entries: readonly EmojiEntry[];
180
+ };
181
+ declare const EMOJI_CATEGORIES: readonly EmojiCategory[];
182
+ /**
183
+ * Busca por prefixo de palavra-chave, não por substring: "ca" traz "casa" e "cartão", mas "sa" não
184
+ * traz "casa" — casar no meio da palavra devolvia resultado que ninguém consegue explicar.
185
+ */
186
+ declare function searchEmojis(query: string): readonly EmojiEntry[];
187
+
188
+ /**
189
+ * Mensagem pronta que o atendente cola no campo com um clique.
190
+ *
191
+ * `text` aceita string com `{{variavel}}` ou função: a string cobre o caso comum (copy fixa com o
192
+ * nome do cliente no meio) sem o host escrever código, e a função cobre o que precisa de lógica —
193
+ * escolher texto por produto, pluralizar, formatar moeda.
194
+ */
195
+ interface QuickReply {
196
+ key: string;
197
+ /** O que aparece no chip, emoji incluso: `👋 Saudação`. */
198
+ label: string;
199
+ text: string | ((variables: Readonly<Record<string, string>>) => string);
200
+ }
201
+ /**
202
+ * Troca `{{nome}}` pelos valores passados. Variável ausente vira string vazia, e não o literal
203
+ * `{{nome}}`: mandar "Olá {{nome}}!" para o cliente é pior que mandar "Olá !".
204
+ */
205
+ declare function applyQuickReplyVariables(template: string, variables?: Readonly<Record<string, string>>): string;
206
+ declare function resolveQuickReply(quickReply: QuickReply, variables?: Readonly<Record<string, string>>): string;
207
+ interface MessageComposerLabels {
208
+ emoji: string;
209
+ attach: string;
210
+ send: string;
211
+ removeAttachment: string;
212
+ }
213
+ declare const DEFAULT_MESSAGE_COMPOSER_LABELS: MessageComposerLabels;
78
214
  interface MessageComposerProps {
215
+ labels?: Partial<MessageComposerLabels>;
79
216
  onSend: (text: string) => void;
80
217
  onAttach?: (file: File) => void;
81
218
  value?: string;
@@ -85,16 +222,130 @@ interface MessageComposerProps {
85
222
  maxLength?: number;
86
223
  disabled?: boolean;
87
224
  acceptedFileTypes?: string;
225
+ /**
226
+ * Ocupa o lugar do botão de enviar enquanto não há nada para enviar — é onde o WhatsApp põe o
227
+ * microfone. Fora do campo, o botão vira um bloco solto ao lado do pill e quebra a barra.
228
+ */
229
+ idleAction?: ReactNode;
230
+ /** Mensagens prontas exibidas acima do campo. Vazio ou ausente, a faixa não é renderizada. */
231
+ quickReplies?: readonly QuickReply[];
232
+ /** Valores para `{{variavel}}` — tipicamente nome do cliente, produto, protocolo. */
233
+ quickReplyVariables?: Readonly<Record<string, string>>;
88
234
  className?: string;
89
235
  classNames?: Partial<MessageComposerClassNames>;
90
236
  }
91
237
  interface MessageComposerClassNames {
92
238
  root: string;
239
+ quickReplies: string;
240
+ quickReply: string;
93
241
  field: string;
94
242
  }
95
- declare const MessageComposer: ({ onSend, onAttach, value: externalValue, onChange: externalOnChange, features, placeholder, maxLength, disabled, acceptedFileTypes, className, classNames, }: MessageComposerProps) => react.JSX.Element;
243
+ /**
244
+ * Exatamente o que a Meta aceita em mensagem de mídia — imagem, sticker, áudio, vídeo e a lista
245
+ * fechada de documentos. Oferecer no seletor um formato que o WhatsApp recusa (`.zip`, `.rtf`)
246
+ * empurra a falha para depois do envio, quando já não dá para explicar ao operador o que houve.
247
+ * Produto com regra própria passa `acceptedFileTypes`.
248
+ */
249
+ declare const DEFAULT_ACCEPTED_FILE_TYPES: string;
250
+ declare const MessageComposer: ({ onSend, onAttach, value: externalValue, onChange: externalOnChange, quickReplies, quickReplyVariables, features, placeholder, maxLength, disabled, acceptedFileTypes, idleAction, className, classNames, labels, }: MessageComposerProps) => react.JSX.Element;
96
251
 
252
+ /** Cada ação que a barra sabe oferecer. `toolbar` decide quais delas aparecem. */
253
+ declare const RICH_COMPOSER_ACTION: {
254
+ readonly BOLD: "bold";
255
+ readonly ITALIC: "italic";
256
+ readonly STRIKETHROUGH: "strikethrough";
257
+ readonly MONOSPACE: "monospace";
258
+ readonly EMOJI: "emoji";
259
+ readonly ATTACH: "attach";
260
+ readonly VARIABLES: "variables";
261
+ };
262
+ type RichComposerAction = (typeof RICH_COMPOSER_ACTION)[keyof typeof RICH_COMPOSER_ACTION];
263
+ /** Texto das dicas. O host troca só o que quiser; o resto fica no padrão. */
264
+ interface RichComposerTooltips {
265
+ bold: string;
266
+ italic: string;
267
+ strikethrough: string;
268
+ monospace: string;
269
+ emoji: string;
270
+ attach: string;
271
+ send: string;
272
+ variables: string;
273
+ /** Botão que abre a formatação recolhida, quando a barra está estreita demais para os quatro. */
274
+ formatting: string;
275
+ }
276
+ declare const DEFAULT_RICH_COMPOSER_TOOLTIPS: RichComposerTooltips;
277
+ /**
278
+ * Um valor que o operador pode inserir no texto sem digitar. `value` é o que entra no campo — pode
279
+ * ser o dado já resolvido ("Anderson") ou um marcador a resolver depois ("{{nome}}"): quem decide é
280
+ * o host, porque só ele sabe se a substituição acontece aqui ou no envio.
281
+ */
282
+ interface RichComposerVariable {
283
+ id: string;
284
+ label: string;
285
+ value: string;
286
+ /** Prévia do que será inserido, para o operador conferir antes de tocar. */
287
+ tooltip?: string;
288
+ }
289
+ /** Uma resposta rápida: o que o operador lê no chip e o que cai no campo ao tocar nele. */
290
+ interface RichComposerQuickReply {
291
+ id: string;
292
+ label: string;
293
+ text: string;
294
+ /** Dica ao passar o mouse. Sem isto, o chip não tem `title` — rótulo curto já se explica. */
295
+ tooltip?: string;
296
+ }
297
+ /** Handle imperativo: `contentEditable` controlado pelo React perde o cursor a cada tecla. */
298
+ interface RichMessageComposerHandle {
299
+ setContent: (text: string) => void;
300
+ clear: () => void;
301
+ focus: () => void;
302
+ }
303
+ interface RichMessageComposerProps {
304
+ /** Texto na notação do WhatsApp (`*negrito*`), não HTML. */
305
+ value: string;
306
+ onChange: (value: string) => void;
307
+ onSend: () => void;
308
+ onAttachFiles?: (files: FileList) => void;
309
+ quickReplies?: RichComposerQuickReply[];
310
+ /** Variáveis que o operador pode inserir no texto. Vazio ou ausente, o botão não aparece. */
311
+ variables?: RichComposerVariable[];
312
+ /**
313
+ * Quais ações aparecem. Ausente, todas aparecem — menos as que não têm como funcionar (anexo sem
314
+ * `onAttachFiles` some sozinho, porque botão que não faz nada é pior que botão nenhum).
315
+ */
316
+ toolbar?: Partial<Record<RichComposerAction, boolean>>;
317
+ tooltips?: Partial<RichComposerTooltips>;
318
+ placeholder?: string;
319
+ disabled?: boolean;
320
+ isSending?: boolean;
321
+ /** Ocupa o lugar do enviar enquanto não há nada para enviar — onde o WhatsApp põe o microfone. */
322
+ idleAction?: ReactNode;
323
+ /** Prévia dos anexos já escolhidos, desenhada pelo host acima da barra. */
324
+ attachmentsPreview?: ReactNode;
325
+ /**
326
+ * Há anexo na fila esperando envio. O campo não conhece a fila — é do host — e sem essa dica ele
327
+ * concluía que não havia nada a enviar: com uma imagem anexada e nenhum texto, o botão de enviar
328
+ * dava lugar ao `idleAction` e a imagem ficava presa.
329
+ */
330
+ hasQueuedAttachments?: boolean;
331
+ acceptedFileTypes?: string;
332
+ className?: string;
333
+ }
334
+ declare const RichMessageComposer: react.ForwardRefExoticComponent<RichMessageComposerProps & react.RefAttributes<RichMessageComposerHandle>>;
335
+
336
+ interface WhatsAppMessageEditorLabels {
337
+ bold: string;
338
+ /** Tooltip da negrito — traz a sintaxe do WhatsApp junto, por isso é separado do `aria-label`. */
339
+ boldHint: string;
340
+ italic: string;
341
+ italicHint: string;
342
+ strikethrough: string;
343
+ strikethroughHint: string;
344
+ insertPlaceholder: (token: string) => string;
345
+ }
346
+ declare const DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS: WhatsAppMessageEditorLabels;
97
347
  interface WhatsAppMessageEditorProps {
348
+ labels?: Partial<WhatsAppMessageEditorLabels>;
98
349
  value: string;
99
350
  onChange: (value: string) => void;
100
351
  placeholder?: string;
@@ -103,7 +354,7 @@ interface WhatsAppMessageEditorProps {
103
354
  previewLabel?: string;
104
355
  emptyPreviewText?: string;
105
356
  }
106
- declare function WhatsAppMessageEditor({ value, onChange, placeholder, placeholders, rows, previewLabel, emptyPreviewText, }: WhatsAppMessageEditorProps): react.JSX.Element;
357
+ declare function WhatsAppMessageEditor({ value, onChange, placeholder, placeholders, rows, previewLabel, emptyPreviewText, labels, }: WhatsAppMessageEditorProps): react.JSX.Element;
107
358
 
108
359
  interface SimpleEmojiPickerProps {
109
360
  onSelect: (emoji: string) => void;
@@ -124,16 +375,30 @@ interface DateDividerProps {
124
375
  }
125
376
  declare function DateDivider({ iso, className, classNames }: DateDividerProps): react.JSX.Element;
126
377
 
378
+ interface AvatarLabels {
379
+ /** Lido por leitor de tela quando não há nome nem imagem — a silhueta genérica. */
380
+ unnamedContact: string;
381
+ }
127
382
  interface AvatarProps {
128
383
  name?: string | null;
129
384
  avatarUrl?: string;
130
385
  size?: 'sm' | 'md' | 'lg';
131
386
  className?: string;
387
+ labels?: Partial<AvatarLabels>;
132
388
  }
133
- declare function Avatar({ name, avatarUrl, size, className }: AvatarProps): react.JSX.Element;
389
+ declare const DEFAULT_AVATAR_LABELS: AvatarLabels;
390
+ declare function Avatar({ name, avatarUrl, size, className, labels }: AvatarProps): react.JSX.Element;
134
391
 
392
+ interface ConversationListItemLabels {
393
+ /** Tooltip do ponto vermelho: a janela de atendimento de 24h já fechou. */
394
+ expiredWindow: string;
395
+ /** Tooltip do ponto laranja: a janela de atendimento está perto de fechar. */
396
+ warningWindow: string;
397
+ }
398
+ declare const DEFAULT_CONVERSATION_LIST_ITEM_LABELS: ConversationListItemLabels;
135
399
  interface ConversationListItemProps {
136
400
  conversation: ConversationSummary;
401
+ labels?: Partial<ConversationListItemLabels>;
137
402
  active?: boolean;
138
403
  selected?: boolean;
139
404
  onClick?: () => void;
@@ -150,7 +415,7 @@ interface ConversationListItemProps {
150
415
  */
151
416
  highlightActive?: boolean;
152
417
  }
153
- declare const ConversationListItem: ({ conversation, active, selected, onClick, onSelect, showDivider, highlightActive, }: ConversationListItemProps) => react.JSX.Element;
418
+ declare const ConversationListItem: ({ conversation, active, selected, onClick, onSelect, showDivider, highlightActive, labels, }: ConversationListItemProps) => react.JSX.Element;
154
419
 
155
420
  type ToastType = 'success' | 'error' | 'info';
156
421
  interface ToastContextValue {
@@ -164,18 +429,41 @@ declare function ToastProvider({ children }: {
164
429
  }): react.JSX.Element;
165
430
  declare function useToast(): ToastContextValue;
166
431
 
432
+ /**
433
+ * Camada única de dicas do pacote.
434
+ *
435
+ * O `title` nativo existia em todos os botões e mesmo assim a dica "não aparecia": o navegador
436
+ * espera de 1 a 2 segundos antes de desenhar, o balão sai fora do tema e some ao menor movimento do
437
+ * mouse. Aqui a dica é do produto — aparece em 120ms, com o mesmo contraste do resto da interface.
438
+ *
439
+ * Um só ouvinte no documento atende a interface inteira: cada botão declara `data-cv-tooltip` e não
440
+ * precisa de estado, ref ou wrapper próprio. O balão é impresso em `document.body` via portal
441
+ * porque `overflow` de container (a régua de respostas rápidas rola na horizontal) recortaria um
442
+ * balão desenhado dentro do próprio botão.
443
+ */
444
+ /** Atributo que marca um elemento como portador de dica. */
445
+ declare const TOOLTIP_ATTRIBUTE = "data-cv-tooltip";
446
+ declare function TooltipLayer(): react.ReactPortal | null;
447
+
167
448
  interface StatusTicksProps {
168
449
  status: string;
169
450
  title?: string;
170
451
  }
171
452
  declare function StatusTicks({ status, title }: StatusTicksProps): react.JSX.Element;
172
453
 
454
+ interface LightboxLabels {
455
+ /** Texto alternativo quando a imagem não tem legenda — sem ele o leitor de tela anuncia a URL. */
456
+ imageAlt: string;
457
+ close: string;
458
+ }
173
459
  interface LightboxProps {
174
460
  imageUrl: string;
175
461
  caption?: string;
176
462
  onClose: () => void;
463
+ labels?: Partial<LightboxLabels>;
177
464
  }
178
- declare function Lightbox({ imageUrl, caption, onClose }: LightboxProps): react.JSX.Element;
465
+ declare const DEFAULT_LIGHTBOX_LABELS: LightboxLabels;
466
+ declare function Lightbox({ imageUrl, caption, onClose, labels }: LightboxProps): react.JSX.Element;
179
467
 
180
468
  interface FileIconProps {
181
469
  filename?: string;
@@ -222,23 +510,23 @@ type ConversationWindow = (typeof CONVERSATION_WINDOW)[keyof typeof CONVERSATION
222
510
  declare const WINDOW_FILTERS: readonly [{
223
511
  readonly value: "all";
224
512
  readonly label: "Todas";
225
- readonly dotClass: "";
513
+ readonly tone: "";
226
514
  }, {
227
515
  readonly value: "fresh";
228
516
  readonly label: "<12h";
229
- readonly dotClass: "bg-green-500";
517
+ readonly tone: "fresh";
230
518
  }, {
231
519
  readonly value: "warning";
232
520
  readonly label: "12-21h";
233
- readonly dotClass: "bg-yellow-500";
521
+ readonly tone: "warning";
234
522
  }, {
235
523
  readonly value: "critical";
236
524
  readonly label: "21-24h";
237
- readonly dotClass: "bg-red-500";
525
+ readonly tone: "critical";
238
526
  }, {
239
527
  readonly value: "expired";
240
528
  readonly label: ">24h";
241
- readonly dotClass: "bg-gray-400";
529
+ readonly tone: "expired";
242
530
  }];
243
531
  type WindowOfParams = {
244
532
  readonly lastInboundAt: string | null;
@@ -307,6 +595,19 @@ interface ConversationHeaderClassNames {
307
595
  desktopActions: string;
308
596
  mobileMenu: string;
309
597
  }
598
+ /**
599
+ * Utilitário extra que o host pendura no cabeçalho — ícone no desktop, item de menu no celular,
600
+ * como os nativos. Entra por aqui, e não por um slot de ReactNode, porque é isso que preserva o
601
+ * comportamento responsivo: um nó solto viraria um quarto ícone em 375px, sem área de toque.
602
+ */
603
+ interface ConversationHeaderUtility {
604
+ key: string;
605
+ /** Ícone da biblioteca (lucide), no tamanho dos utilitários nativos: `<Play size={16} />`. */
606
+ icon: ReactNode;
607
+ label: string;
608
+ run: () => void;
609
+ active?: boolean;
610
+ }
310
611
  interface ConversationHeaderProps {
311
612
  conversation: ConversationSummary;
312
613
  busy?: boolean;
@@ -316,29 +617,46 @@ interface ConversationHeaderProps {
316
617
  onDownload?: () => void;
317
618
  onOpenDocuments?: () => void;
318
619
  documentsOpen?: boolean;
620
+ /** Ações do produto que não existem no contrato do pacote (ex.: ferramentas de dev). */
621
+ extraUtilities?: readonly ConversationHeaderUtility[];
319
622
  onBack?: () => void;
320
623
  labels?: Partial<ConversationHeaderLabels>;
321
624
  className?: string;
322
625
  classNames?: Partial<ConversationHeaderClassNames>;
323
626
  }
324
- declare function ConversationHeader({ conversation, busy, onTakeover, onReturnToBot, onFinish, onDownload, onOpenDocuments, documentsOpen, onBack, labels: labelsOverride, className, classNames, }: ConversationHeaderProps): react.JSX.Element;
627
+ declare function ConversationHeader({ conversation, busy, onTakeover, onReturnToBot, onFinish, onDownload, onOpenDocuments, documentsOpen, extraUtilities, onBack, labels: labelsOverride, className, classNames, }: ConversationHeaderProps): react.JSX.Element;
325
628
 
326
629
  /**
327
630
  * "Suas Seleções": o que o bot já coletou na conversa. Para o atendente que assume no meio, é a
328
- * diferença entre ler o transcript inteiro e ver o estado em duas linhas.
631
+ * diferença entre ler o transcript inteiro e ver o estado de relance.
329
632
  *
330
633
  * O pacote não interpreta o contexto — ele é `Record<string, unknown>` e cada produto nomeia as
331
634
  * próprias chaves. O host traduz para `entries`; aqui só se decide como mostrar.
635
+ *
636
+ * Desenho em paridade com financiamento-imobiliario-bot/apps/web/src/components/SelectionsSummary.tsx:
637
+ * card com gradiente, badge de contagem, pills de status no cabeçalho e grid de cards com borda
638
+ * colorida por estado. O que ficou diferente de lá, e por quê, está comentado no ponto.
332
639
  */
640
+ /**
641
+ * `completed` tem valor, `pending` ainda não foi coletado, `editing` é o cliente refazendo a
642
+ * resposta. O host só precisa mandar `status` para o terceiro caso — os dois primeiros saem do
643
+ * próprio `value`, e exigir o campo quebraria quem já usa o painel.
644
+ */
645
+ type ConversationContextStatus = 'completed' | 'pending' | 'editing';
333
646
  interface ConversationContextEntry {
334
647
  key: string;
335
648
  label: string;
336
649
  value?: string | undefined;
337
650
  icon?: string;
651
+ status?: ConversationContextStatus;
338
652
  }
339
653
  interface ConversationContextPanelLabels {
340
654
  title: string;
341
655
  empty: string;
656
+ collapse: string;
657
+ expand: string;
658
+ /** Placeholder do card ainda não coletado. */
659
+ notCollected: string;
342
660
  }
343
661
  declare const DEFAULT_CONVERSATION_CONTEXT_LABELS: ConversationContextPanelLabels;
344
662
  interface ConversationContextPanelClassNames {
@@ -349,11 +667,23 @@ interface ConversationContextPanelClassNames {
349
667
  }
350
668
  interface ConversationContextPanelProps {
351
669
  entries: readonly ConversationContextEntry[];
670
+ /**
671
+ * Estado inicial. Ausente, abre sozinho no desktop quando há algum dado preenchido.
672
+ *
673
+ * Existe porque "abre sozinho" nem sempre é o que o produto quer: com 1 de 6 campos preenchidos o
674
+ * painel ocupa altura mostrando quase só pendências, e empurra a conversa — que é o que se veio ver.
675
+ */
676
+ defaultOpen?: boolean;
677
+ /**
678
+ * Rótulo do fluxo em curso, exibido em azul ao lado do título — no financiamento é o produto
679
+ * escolhido ("Consórcio", "MCMV"). Ausente, o cabeçalho fica só com título e contagens.
680
+ */
681
+ flowLabel?: string;
352
682
  labels?: Partial<ConversationContextPanelLabels>;
353
683
  className?: string;
354
684
  classNames?: Partial<ConversationContextPanelClassNames>;
355
685
  }
356
- declare function ConversationContextPanel({ entries, labels: labelsOverride, className, classNames, }: ConversationContextPanelProps): react.JSX.Element;
686
+ declare function ConversationContextPanel({ entries, defaultOpen, flowLabel, labels: labelsOverride, className, classNames, }: ConversationContextPanelProps): react.JSX.Element;
357
687
 
358
688
  interface WindowExpiredNoticeLabels {
359
689
  title: string;
@@ -373,6 +703,217 @@ declare function WindowExpiredNotice({ onSendTemplate, disabled, labels: labelsO
373
703
  */
374
704
  declare function isWindowBlocking(window: ConversationWindow): boolean;
375
705
 
706
+ /**
707
+ * Biblioteca de arquivos de TODAS as conversas — a tela de Documentos do painel, fora do
708
+ * atendimento.
709
+ *
710
+ * Distinta do `ConversationDocumentsPanel`: aquele parte de uma conversa aberta e vive dentro dela;
711
+ * esta varre a empresa e por isso mostra de qual conversa cada arquivo veio, com o número
712
+ * clicável. Sem essa referência, uma lista global de anexos não responde nenhuma pergunta.
713
+ */
714
+ interface DocumentsLibraryLabels {
715
+ title: string;
716
+ searchPlaceholder: string;
717
+ empty: string;
718
+ noResults: string;
719
+ loading: string;
720
+ failure: string;
721
+ view: string;
722
+ download: string;
723
+ openConversation: string;
724
+ sourceFilterAll: string;
725
+ sourceFilterCustomer: string;
726
+ sourceFilterTeam: string;
727
+ sortMostRecent: string;
728
+ sortOldest: string;
729
+ clearFilters: string;
730
+ upload: string;
731
+ uploadError: string;
732
+ total: (count: number) => string;
733
+ page: (current: number, last: number) => string;
734
+ }
735
+ declare const DEFAULT_DOCUMENTS_LIBRARY_LABELS: DocumentsLibraryLabels;
736
+ interface DocumentsLibraryClassNames {
737
+ root: string;
738
+ title: string;
739
+ filters: string;
740
+ search: string;
741
+ sourceSelect: string;
742
+ sortButton: string;
743
+ clearButton: string;
744
+ status: string;
745
+ list: string;
746
+ item: string;
747
+ conversationLink: string;
748
+ filename: string;
749
+ meta: string;
750
+ pagination: string;
751
+ }
752
+ interface DocumentsLibraryProps {
753
+ /** Itens por página. O total vem do servidor. */
754
+ perPage?: number;
755
+ /** Abrir a conversa de origem. Ausente, o número aparece como texto e não como link. */
756
+ onOpenConversation?: (conversationId: string) => void;
757
+ labels?: Partial<DocumentsLibraryLabels>;
758
+ className?: string;
759
+ classNames?: Partial<DocumentsLibraryClassNames>;
760
+ }
761
+ declare function DocumentsLibrary({ perPage, onOpenConversation, labels: labelsOverride, className, classNames, }: DocumentsLibraryProps): react.JSX.Element | null;
762
+
763
+ type SortDirection = 'asc' | 'desc';
764
+ interface SortableHeadProps {
765
+ readonly label: string;
766
+ readonly field: string;
767
+ readonly activeField: string;
768
+ readonly direction: SortDirection;
769
+ readonly onSort: (field: string) => void;
770
+ readonly className?: string;
771
+ }
772
+ declare function SortableHead({ label, field, activeField, direction, onSort, className }: SortableHeadProps): react.JSX.Element;
773
+ interface FilterOption {
774
+ readonly value: string;
775
+ readonly label: string;
776
+ }
777
+ interface MultiSelectFilterProps {
778
+ readonly label: string;
779
+ readonly options: readonly FilterOption[];
780
+ readonly selected: readonly string[];
781
+ readonly onChange: (selected: readonly string[]) => void;
782
+ readonly className?: string;
783
+ }
784
+ declare function MultiSelectFilter({ label, options, selected, onChange, className }: MultiSelectFilterProps): react.JSX.Element;
785
+ interface BulkActionBarProps {
786
+ readonly selectedCount: number;
787
+ readonly selectedLabel: (count: number) => string;
788
+ readonly clearLabel: string;
789
+ readonly onClear: () => void;
790
+ readonly children?: ReactNode;
791
+ }
792
+ declare function BulkActionBar({ selectedCount, selectedLabel, clearLabel, onClear, children }: BulkActionBarProps): react.JSX.Element | null;
793
+ interface ListingPaginationProps {
794
+ readonly page: number;
795
+ readonly total: number;
796
+ readonly perPage: number;
797
+ readonly perPageOptions?: readonly number[];
798
+ readonly onPageChange: (page: number) => void;
799
+ readonly onPerPageChange?: (perPage: number) => void;
800
+ readonly labels: {
801
+ readonly show: string;
802
+ readonly perPage: string;
803
+ readonly total: (count: number) => string;
804
+ readonly page: (current: number, last: number) => string;
805
+ readonly previous: string;
806
+ readonly next: string;
807
+ };
808
+ }
809
+ declare function ListingPagination({ page, total, perPage, perPageOptions, onPageChange, onPerPageChange, labels, }: ListingPaginationProps): react.JSX.Element;
810
+
811
+ /**
812
+ * Vocabulário da biblioteca de arquivos. Sobrescrevível campo a campo: o produto troca "cliente"
813
+ * por "lead" ou o idioma inteiro sem manter uma cópia da tela para isso.
814
+ */
815
+ interface DocumentsWorkspaceLabels {
816
+ readonly title: string;
817
+ readonly subtitle: (total: number) => string;
818
+ readonly searchPlaceholder: string;
819
+ readonly empty: string;
820
+ readonly noResults: string;
821
+ readonly loading: string;
822
+ readonly failure: string;
823
+ readonly view: string;
824
+ readonly download: string;
825
+ readonly remove: string;
826
+ readonly removeConfirm: (filename: string) => string;
827
+ readonly openConversation: string;
828
+ readonly sourceFilter: string;
829
+ readonly categoryFilter: string;
830
+ readonly startDate: string;
831
+ readonly endDate: string;
832
+ readonly clearFilters: string;
833
+ readonly selectAllPage: string;
834
+ readonly selectRow: string;
835
+ readonly bulkSelected: (count: number) => string;
836
+ readonly bulkClear: string;
837
+ readonly bulkDownloadZip: string;
838
+ readonly bulkRemove: (count: number) => string;
839
+ readonly bulkRemoveConfirm: (count: number) => string;
840
+ readonly upload: string;
841
+ readonly uploadError: string;
842
+ readonly columnFilename: string;
843
+ readonly columnContact: string;
844
+ readonly columnType: string;
845
+ readonly columnSize: string;
846
+ readonly columnSource: string;
847
+ readonly columnDate: string;
848
+ readonly columnActions: string;
849
+ readonly sourceLabels: Readonly<Record<string, string>>;
850
+ readonly categoryLabels: Readonly<Record<string, string>>;
851
+ readonly show: string;
852
+ readonly perPage: string;
853
+ readonly total: (count: number) => string;
854
+ readonly page: (current: number, last: number) => string;
855
+ readonly previousPage: string;
856
+ readonly nextPage: string;
857
+ }
858
+ declare const DEFAULT_DOCUMENTS_WORKSPACE_LABELS: DocumentsWorkspaceLabels;
859
+
860
+ interface DocumentsWorkspaceClassNames {
861
+ root: string;
862
+ header: string;
863
+ filters: string;
864
+ table: string;
865
+ row: string;
866
+ status: string;
867
+ }
868
+ interface DocumentsWorkspaceProps {
869
+ readonly perPage?: number;
870
+ readonly perPageOptions?: readonly number[];
871
+ /** Abrir a conversa de origem. Ausente, o número aparece como texto e não como link. */
872
+ readonly onOpenConversation?: (conversationId: string) => void;
873
+ /** Origens filtráveis. Ausente, usa o vocabulário padrão (`customer`, `agent`, `bot`). */
874
+ readonly sources?: readonly FilterOption[];
875
+ /** Categorias de arquivo. Lista vazia esconde o filtro — nem todo host classifica anexo. */
876
+ readonly categories?: readonly FilterOption[];
877
+ /** Recorte por data. Desligado quando o backend não sabe filtrar por período. */
878
+ readonly dateFilter?: boolean;
879
+ /**
880
+ * Filtros do produto (cliente, unidade, campanha). Recebe os parâmetros extras atuais e devolve
881
+ * os controles; o que o produto guardar aqui viaja em `extra` para o `getAllDocuments`.
882
+ */
883
+ readonly renderFilters?: (context: DocumentsFiltersContext) => ReactNode;
884
+ readonly labels?: Partial<DocumentsWorkspaceLabels>;
885
+ readonly className?: string;
886
+ readonly classNames?: Partial<DocumentsWorkspaceClassNames>;
887
+ /** Espelhar filtros e paginação na URL. Desligado em preview, onde não há rota de verdade. */
888
+ readonly syncUrl?: boolean;
889
+ }
890
+ interface DocumentsFiltersContext {
891
+ readonly extra: Readonly<Record<string, string | number>>;
892
+ readonly setExtra: (next: Readonly<Record<string, string | number>>) => void;
893
+ }
894
+ declare function DocumentsWorkspace({ perPage: initialPerPage, perPageOptions, onOpenConversation, sources, categories, dateFilter, renderFilters, labels: labelsOverride, className, classNames, syncUrl, }: DocumentsWorkspaceProps): react.JSX.Element | null;
895
+
896
+ /**
897
+ * Estado de listagem espelhado na URL — ordenação, filtros e paginação (regra `web.md` §7).
898
+ *
899
+ * Escrito sobre `history.replaceState` e não sobre um router: o pacote roda em três produtos com
900
+ * routers diferentes, e exigir um deles arrastaria dependência de framework para dentro do módulo.
901
+ * `replaceState` também é o comportamento certo aqui — filtrar não é navegar, e cada tecla digitada
902
+ * na busca não deve virar uma entrada no botão "voltar".
903
+ */
904
+ /** `enabled: false` mantém o mesmo contrato de estado sem tocar na URL — para uso em preview e teste. */
905
+ interface UrlStateOptions {
906
+ readonly enabled?: boolean;
907
+ }
908
+ declare function useUrlStringState(key: string, initial: string, { enabled }?: UrlStateOptions): [string, (next: string) => void];
909
+ declare function useUrlNumberState(key: string, initial: number, { enabled }?: UrlStateOptions): [number, (next: number) => void];
910
+ declare function useUrlArrayState(key: string, { enabled }?: UrlStateOptions): [readonly string[], (next: readonly string[]) => void];
911
+ /**
912
+ * Espera o usuário parar de digitar antes de deixar o valor chegar à query. Sem isto, cada tecla
913
+ * na busca vira uma chamada de rede e uma reescrita de URL.
914
+ */
915
+ declare function useDebouncedValue<TValue>(value: TValue, delayMs?: number): TValue;
916
+
376
917
  /**
377
918
  * Arquivos trocados na conversa. Sai do transcript e vira lista própria porque anexo é o que o
378
919
  * atendente mais precisa reencontrar depois — rolar meses de mensagens para achar um comprovante é
@@ -381,29 +922,76 @@ declare function isWindowBlocking(window: ConversationWindow): boolean;
381
922
  * Usa `useConversationDocuments`, então funciona com qualquer `ConversationsApi`. Host sem
382
923
  * biblioteca de documentos cai no estado vazio, sem quebrar.
383
924
  */
925
+ /** Origens que o filtro oferece. `all` não é origem — é a ausência de filtro. */
926
+ declare const DOCUMENT_SOURCE_FILTER: {
927
+ readonly ALL: "all";
928
+ readonly CUSTOMER: "customer";
929
+ readonly TEAM: "team";
930
+ };
931
+ type DocumentSourceFilter = (typeof DOCUMENT_SOURCE_FILTER)[keyof typeof DOCUMENT_SOURCE_FILTER];
384
932
  interface ConversationDocumentsPanelLabels {
385
933
  toggle: string;
386
934
  title: string;
387
935
  searchPlaceholder: string;
388
936
  empty: string;
937
+ /** Distinto de `empty`: sem resultado POR CAUSA do filtro, e não conversa sem anexo nenhum. */
938
+ noResults: string;
389
939
  loading: string;
390
940
  failure: string;
391
941
  download: string;
942
+ view: string;
943
+ sourceFilterAll: string;
944
+ sourceFilterCustomer: string;
945
+ sourceFilterTeam: string;
946
+ sortMostRecent: string;
947
+ sortOldest: string;
948
+ clearFilters: string;
949
+ selectAll: string;
950
+ downloadSelected: (count: number) => string;
951
+ archiveFailed: string;
952
+ total: (count: number) => string;
953
+ page: (current: number, last: number) => string;
392
954
  }
393
955
  declare const DEFAULT_CONVERSATION_DOCUMENTS_LABELS: ConversationDocumentsPanelLabels;
956
+ /**
957
+ * Partes estilizáveis do painel, no mesmo contrato do `ConversationHeader`: `cn` funde por cima da
958
+ * base e conflito de utilitário (padding, tamanho de fonte, borda) fica com o valor do produto.
959
+ *
960
+ * `status` cobre carregando/erro/vazio de uma vez — são a mesma linha de texto auxiliar, e slots
961
+ * separados só multiplicariam chave para quem quer mudar a cor de aviso.
962
+ */
394
963
  interface ConversationDocumentsPanelClassNames {
395
964
  root: string;
396
965
  body: string;
966
+ title: string;
967
+ filters: string;
968
+ search: string;
969
+ sourceSelect: string;
970
+ sortButton: string;
971
+ clearButton: string;
972
+ status: string;
973
+ list: string;
974
+ item: string;
975
+ sourceBadge: string;
976
+ filename: string;
977
+ meta: string;
978
+ viewButton: string;
979
+ downloadButton: string;
980
+ pagination: string;
981
+ selectionBar: string;
982
+ checkbox: string;
397
983
  }
398
984
  interface ConversationDocumentsPanelProps {
399
985
  conversationId: string;
400
986
  /** Controlado de fora porque o gatilho vive no cabeçalho, junto das outras ações da conversa. */
401
987
  open: boolean;
988
+ /** Itens por página. O total vem do servidor; sem paginação no host, a barra não aparece. */
989
+ perPage?: number;
402
990
  labels?: Partial<ConversationDocumentsPanelLabels>;
403
991
  className?: string;
404
992
  classNames?: Partial<ConversationDocumentsPanelClassNames>;
405
993
  }
406
- declare function ConversationDocumentsPanel({ conversationId, open, labels: labelsOverride, className, classNames, }: ConversationDocumentsPanelProps): react.JSX.Element | null;
994
+ declare function ConversationDocumentsPanel({ conversationId, open, perPage, labels: labelsOverride, className, classNames, }: ConversationDocumentsPanelProps): react.JSX.Element | null;
407
995
 
408
996
  /**
409
997
  * Serialização do transcript para download. Fica no pacote porque o formato de um histórico de
@@ -454,11 +1042,35 @@ declare function useDarkMode(): {
454
1042
  declare const NARROW_MAX_WIDTH_PX = 1023;
455
1043
  declare function useIsNarrow(): boolean;
456
1044
 
1045
+ interface UseWaitingNotificationsLabels {
1046
+ /** Título da notificação do sistema. Recebe a conversa para o host escolher nome × número. */
1047
+ title: (conversation: ConversationSummary) => string;
1048
+ body: (conversation: ConversationSummary) => string;
1049
+ }
1050
+ interface UseWaitingNotificationsParams {
1051
+ /**
1052
+ * Repassado cru ao `fetchConversations`. É o que permite filtrar não lidas **no servidor** em
1053
+ * vez de baixar a lista inteira e contar no cliente: um painel com milhares de conversas não
1054
+ * pode paginar 50 por vez atrás de quem tem `unread > 0`.
1055
+ */
1056
+ readonly params?: ListConversationsParams;
1057
+ readonly intervalMs?: number;
1058
+ /** Desliga o polling sem desmontar quem chama — útil com a aba em segundo plano. */
1059
+ readonly enabled?: boolean;
1060
+ readonly icon?: string;
1061
+ readonly labels?: Partial<UseWaitingNotificationsLabels>;
1062
+ }
457
1063
  interface UseWaitingNotificationsResult {
458
1064
  unreadCount: number;
459
1065
  conversations: ConversationSummary[];
1066
+ /**
1067
+ * Releitura sob demanda. Existe porque o polling é o piso, não o mecanismo: quem já recebe SSE
1068
+ * ou acabou de marcar tudo como lido sabe da mudança antes do próximo tick, e esperar 10s para
1069
+ * o contador acompanhar faz a interface parecer travada.
1070
+ */
1071
+ refresh: () => Promise<void>;
460
1072
  }
461
- declare function useWaitingNotifications(): UseWaitingNotificationsResult;
1073
+ declare function useWaitingNotifications(params?: UseWaitingNotificationsParams): UseWaitingNotificationsResult;
462
1074
 
463
1075
  interface ConversationsContextValue {
464
1076
  api: ConversationsApi;
@@ -540,6 +1152,7 @@ interface WhatsAppCreateTemplateFormLabels {
540
1152
  sectionDescription: string;
541
1153
  nameLabel: string;
542
1154
  nameHint: string;
1155
+ namePlaceholder: string;
543
1156
  categoryLabel: string;
544
1157
  languageLabel: string;
545
1158
  headerLabel: string;
@@ -605,6 +1218,47 @@ interface WelcomeFarewellFormProps {
605
1218
  }
606
1219
  declare function WelcomeFarewellForm({ welcomeMessage, onWelcomeMessageChange, farewellMessage, onFarewellMessageChange, onSave, saving, saveSuccess, welcomePlaceholders, farewellPlaceholders, labels: labelsOverride, }: WelcomeFarewellFormProps): react.JSX.Element;
607
1220
 
1221
+ interface TranscriptionSettingsFormLabels {
1222
+ sectionTitle: string;
1223
+ enabled: string;
1224
+ enabledHint: string;
1225
+ modeTitle: string;
1226
+ modeAuto: string;
1227
+ modeAutoHint: string;
1228
+ modeOnDemand: string;
1229
+ modeOnDemandHint: string;
1230
+ unavailable: string;
1231
+ save: string;
1232
+ saving: string;
1233
+ saveSuccess: string;
1234
+ }
1235
+ interface TranscriptionSettingsFormProps {
1236
+ enabled: boolean;
1237
+ onEnabledChange: (value: boolean) => void;
1238
+ mode: TranscriptionMode;
1239
+ onModeChange: (value: TranscriptionMode) => void;
1240
+ onSave: (event: FormEvent) => void;
1241
+ /**
1242
+ * A capacidade existe no servidor (engine e credencial configurados)?
1243
+ *
1244
+ * Distinto de `enabled`: isto é "o ambiente consegue", aquilo é "esta empresa quer". Sem a
1245
+ * distinção, um lojista ligaria o interruptor num ambiente sem engine e concluiria que o produto
1246
+ * está quebrado — o texto nunca apareceria e nada explicaria por quê.
1247
+ */
1248
+ isAvailable?: boolean;
1249
+ saving?: boolean;
1250
+ saveSuccess?: boolean;
1251
+ labels?: Partial<TranscriptionSettingsFormLabels>;
1252
+ }
1253
+ /**
1254
+ * Interruptor de transcrição por empresa, para a tela de configurações.
1255
+ *
1256
+ * Puramente apresentacional, como os outros forms daqui: quem persiste é o host. O pacote não sabe a
1257
+ * rota, e a política vive nas configurações do módulo (`settings.transcriptionEnabled`), não em
1258
+ * variável de ambiente — mudar de ideia sobre transcrever não deveria exigir deploy.
1259
+ */
1260
+ declare function TranscriptionSettingsForm({ enabled, onEnabledChange, mode, onModeChange, onSave, isAvailable, saving, saveSuccess, labels: labelsOverride, }: TranscriptionSettingsFormProps): react.JSX.Element;
1261
+
608
1262
  declare const TEMPLATE_SETTINGS_TAB: {
609
1263
  readonly SELECT: "select";
610
1264
  readonly CREATE: "create";
@@ -635,10 +1289,13 @@ interface WhatsAppTemplatesSettingsProps {
635
1289
  onSubmit: (event: FormEvent) => void;
636
1290
  submitting?: boolean;
637
1291
  result?: WhatsAppCreateTemplateResult | null;
1292
+ labels?: Partial<WhatsAppCreateTemplateFormLabels>;
638
1293
  };
639
1294
  labels?: Partial<WhatsAppTemplatesSettingsLabels>;
1295
+ /** Vocabulário do formulário de seleção — separado de `labels`, que nomeia só as abas daqui. */
1296
+ settingsLabels?: Partial<WhatsAppTemplateSettingsFormLabels>;
640
1297
  }
641
- declare function WhatsAppTemplatesSettings({ labels: labelsOverride, create, ...settingsProps }: WhatsAppTemplatesSettingsProps): react.JSX.Element;
1298
+ declare function WhatsAppTemplatesSettings({ labels: labelsOverride, settingsLabels, create, ...settingsProps }: WhatsAppTemplatesSettingsProps): react.JSX.Element;
642
1299
 
643
1300
  interface TopicItem {
644
1301
  key: string;
@@ -664,6 +1321,67 @@ interface TopicsFormProps {
664
1321
  }
665
1322
  declare function TopicsForm({ topics, onToggle, onMessageChange, onSave, saving, saveSuccess, labels: labelsOverride, }: TopicsFormProps): react.JSX.Element;
666
1323
 
1324
+ interface BotMessages {
1325
+ welcomeMessage: string;
1326
+ farewellMessage: string;
1327
+ }
1328
+ interface TemplateSettings {
1329
+ templateName: string;
1330
+ templateLanguage: string;
1331
+ variables: string[];
1332
+ }
1333
+ interface TranscriptionSettings {
1334
+ enabled: boolean;
1335
+ mode: TranscriptionMode;
1336
+ available: boolean;
1337
+ }
1338
+ interface MessagesWorkspaceApi {
1339
+ getMessages(): Promise<BotMessages>;
1340
+ saveMessages(messages: BotMessages): Promise<void>;
1341
+ /** Sem este par, a seção de tópicos não é desenhada. */
1342
+ getTopics?(): Promise<TopicItem[]>;
1343
+ saveTopics?(topics: TopicItem[]): Promise<void>;
1344
+ /** Sem este par, a aba de templates não é desenhada. */
1345
+ getTemplateSettings?(): Promise<TemplateSettings>;
1346
+ saveTemplateSettings?(settings: TemplateSettings): Promise<void>;
1347
+ /**
1348
+ * Lista de templates aprovados na Meta. Ausente, a aba ainda existe (dá para salvar o nome
1349
+ * escolhido), mas nasce sem opções e sem botão de recarregar.
1350
+ */
1351
+ listTemplates?(): Promise<WhatsAppTemplateSummary[]>;
1352
+ /** Sem isto, o submenu "Criar template" some. */
1353
+ createTemplate?(input: WhatsAppCreateTemplateState): Promise<WhatsAppCreateTemplateResult>;
1354
+ /** Sem este par, a aba de transcrição não é desenhada. */
1355
+ getTranscription?(): Promise<TranscriptionSettings>;
1356
+ saveTranscription?(settings: Omit<TranscriptionSettings, 'available'>): Promise<void>;
1357
+ }
1358
+ interface MessagesWorkspaceLabels {
1359
+ title: string;
1360
+ subtitle: string;
1361
+ loading: string;
1362
+ loadError: string;
1363
+ tabBot: string;
1364
+ tabTemplates: string;
1365
+ tabTranscription: string;
1366
+ welcomeFarewell: Partial<WelcomeFarewellFormLabels>;
1367
+ topics: Partial<TopicsFormLabels>;
1368
+ templates: Partial<WhatsAppTemplatesSettingsLabels>;
1369
+ templateSettings: Partial<WhatsAppTemplateSettingsFormLabels>;
1370
+ createTemplate: Partial<WhatsAppCreateTemplateFormLabels>;
1371
+ transcription: Partial<TranscriptionSettingsFormLabels>;
1372
+ }
1373
+ interface MessagesWorkspaceProps {
1374
+ readonly api: MessagesWorkspaceApi;
1375
+ readonly labels?: Partial<MessagesWorkspaceLabels>;
1376
+ readonly welcomePlaceholders?: readonly string[];
1377
+ readonly farewellPlaceholders?: readonly string[];
1378
+ readonly availableVariables?: WhatsAppTemplateVariableSuggestion[];
1379
+ /** Aviso do produto acima da aba de templates (ex.: rota da Graph API ainda não implementada). */
1380
+ readonly renderTemplatesNotice?: () => ReactNode;
1381
+ readonly className?: string;
1382
+ }
1383
+ declare function MessagesWorkspace({ api, labels: labelsOverride, welcomePlaceholders, farewellPlaceholders, availableVariables, renderTemplatesNotice, className, }: MessagesWorkspaceProps): react.JSX.Element;
1384
+
667
1385
  interface UseConversationMessagesResult {
668
1386
  messages: MessagePayload[];
669
1387
  loading: boolean;
@@ -677,7 +1395,7 @@ interface UseConversationMessagesResult {
677
1395
  caption?: string;
678
1396
  }) => Promise<MessagePayload>;
679
1397
  sendTemplate: (data: {
680
- templateName: string;
1398
+ templateName?: string;
681
1399
  languageCode?: string;
682
1400
  bodyParams?: string[];
683
1401
  }) => Promise<void>;
@@ -688,14 +1406,28 @@ declare function useConversationMessages(conversationId: string, params?: {
688
1406
  before?: string;
689
1407
  }): UseConversationMessagesResult;
690
1408
 
691
- interface UseConversationListParams {
692
- page?: number;
693
- limit?: number;
694
- waitingHuman?: boolean;
695
- search?: string;
696
- }
1409
+ type UseScrollToLatestMessageParams = {
1410
+ /** Troca de conversa. Muda ⇒ salto instantâneo para o fim. */
1411
+ readonly conversationId: string | undefined;
1412
+ /** Quantidade de mensagens carregadas. Cresce ⇒ acompanha o fim, se o operador estiver lá. */
1413
+ readonly messageCount: number;
1414
+ };
1415
+ type UseScrollToLatestMessageResult = {
1416
+ /** Vai no elemento que rola — tipicamente o `ConversationWallpaper`. */
1417
+ readonly containerRef: RefObject<HTMLDivElement | null>;
1418
+ /** Ligue no `onScroll` do mesmo elemento: é o que detecta o operador lendo o histórico. */
1419
+ readonly handleScroll: (event: UIEvent<HTMLDivElement>) => void;
1420
+ /** `true` quando o operador rolou para trás — serve a um botão "ir para a última". */
1421
+ readonly isAwayFromBottom: boolean;
1422
+ readonly scrollToBottom: (behavior?: ScrollBehavior) => void;
1423
+ };
1424
+ declare function useScrollToLatestMessage({ conversationId, messageCount, }: UseScrollToLatestMessageParams): UseScrollToLatestMessageResult;
1425
+
1426
+ type UseConversationListParams = ListConversationsParams;
697
1427
  interface UseConversationListResult {
698
1428
  conversations: ConversationSummary[];
1429
+ /** Total no servidor. Cai para o tamanho da página quando a API devolve só o array. */
1430
+ total: number;
699
1431
  loading: boolean;
700
1432
  error: Error | undefined;
701
1433
  refetch: () => Promise<void>;
@@ -710,12 +1442,11 @@ interface UseConversationContextResult {
710
1442
  }
711
1443
  declare function useConversationContext(conversationId: string): UseConversationContextResult;
712
1444
 
713
- interface UseConversationDocumentsParams {
714
- search?: string;
715
- page?: number;
716
- }
1445
+ type UseConversationDocumentsParams = ListDocumentsParams;
717
1446
  interface UseConversationDocumentsResult {
718
1447
  documents: ConversationDocument[];
1448
+ /** Total no servidor. Cai para o tamanho da página quando a API devolve só o array. */
1449
+ total: number;
719
1450
  loading: boolean;
720
1451
  error: Error | undefined;
721
1452
  refetch: () => Promise<void>;
@@ -726,6 +1457,27 @@ type ConversationRealtimeHandler = (event: MessageEvent) => void;
726
1457
  declare function useConversationRealtime(conversationId: string | undefined, onEvent: ConversationRealtimeHandler): void;
727
1458
  declare function useGlobalRealtime(onEvent: ConversationRealtimeHandler): void;
728
1459
 
1460
+ interface UseConversationActionsResult {
1461
+ /** `undefined` quando a API do host não implementa a operação — a UI esconde a afordância. */
1462
+ takeover: (() => Promise<void>) | undefined;
1463
+ release: (() => Promise<void>) | undefined;
1464
+ finalize: (() => Promise<void>) | undefined;
1465
+ }
1466
+ /**
1467
+ * Ações de atendimento de UMA conversa, já ligadas ao id.
1468
+ *
1469
+ * Separado de `useConversationMessages` porque assumir e devolver conversa também acontece a
1470
+ * partir da lista, onde nenhuma thread está aberta — embutir nas mensagens obrigaria a carregar
1471
+ * a thread inteira só para desenhar um botão na linha.
1472
+ */
1473
+ declare function useConversationActions(conversationId: string): UseConversationActionsResult;
1474
+ interface UseInboxActionsResult {
1475
+ markAllRead: (() => Promise<void>) | undefined;
1476
+ listTemplates: (() => Promise<ConversationTemplate[]>) | undefined;
1477
+ }
1478
+ /** Ações que valem para a caixa inteira, sem conversa selecionada. */
1479
+ declare function useInboxActions(): UseInboxActionsResult;
1480
+
729
1481
  declare function parseWhatsAppFormatting(text: string): ReactNode[];
730
1482
  declare function waToHTML(text: string): string;
731
1483
  declare function htmlToWA(html: string): string;
@@ -735,6 +1487,8 @@ declare function formatPhone(number: string): string;
735
1487
  declare function phoneInitials(number: string): string;
736
1488
 
737
1489
  declare function formatTimestamp(timestamp: string): string;
1490
+ declare function formatDateTime(iso: string): string;
1491
+ declare function isSameDay(a: Date, b: Date): boolean;
738
1492
  declare function formatFileSize(bytes: number): string;
739
1493
 
740
1494
  interface AsyncResourceState<T> {
@@ -744,4 +1498,282 @@ interface AsyncResourceState<T> {
744
1498
  refetch: () => Promise<void>;
745
1499
  }
746
1500
 
747
- export { type AsyncResourceState, AudioPlayer, type AudioPlayerProps, Avatar, type AvatarProps, type BuildTranscriptTextParams, CHANNEL_BRAND_COLOR, CONVERSATION_WINDOW, ChannelIcon, type ChannelIconProps, ConversationChannel, type ConversationContextEntry, ConversationContextPanel, type ConversationContextPanelClassNames, type ConversationContextPanelLabels, type ConversationContextPanelProps, ConversationDocument, ConversationDocumentsPanel, type ConversationDocumentsPanelClassNames, type ConversationDocumentsPanelLabels, type ConversationDocumentsPanelProps, ConversationHeader, type ConversationHeaderClassNames, type ConversationHeaderLabels, type ConversationHeaderProps, ConversationListItem, type ConversationListItemProps, type ConversationLocales, ConversationLocalesProvider, type ConversationLocalesProviderProps, type ConversationRealtimeHandler, ConversationRow, type ConversationRowClassNames, type ConversationRowProps, ConversationSummary, ConversationWallpaper, type ConversationWallpaperProps, type ConversationWindow, ConversationsApi, ConversationsFeatures, ConversationsProvider, DEFAULT_CONVERSATION_CONTEXT_LABELS, DEFAULT_CONVERSATION_DOCUMENTS_LABELS, DEFAULT_CONVERSATION_HEADER_LABELS, DEFAULT_TEMPLATES_SETTINGS_LABELS, DEFAULT_WINDOW_EXPIRED_LABELS, DateDivider, type DateDividerClassNames, type DateDividerProps, EmojiPicker, type EmojiPickerProps, FileIcon, type FileIconProps, Lightbox, type LightboxProps, MediaRenderer, type MediaRendererProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerClassNames, type MessageComposerProps, MessagePayload, MessageTail, MessageText, type MessageTextProps, MessageTimestamp, NARROW_MAX_WIDTH_PX, type ResolveMediaUrl, SSEProvider, SimpleEmojiPicker, type SimpleEmojiPickerProps, StatusTicks, type StatusTicksProps, TEMPLATE_SETTINGS_TAB, type TemplateSettingsTab, ToastProvider, type TopicItem, TopicsForm, type TopicsFormLabels, type TopicsFormProps, type UseConversationContextResult, type UseConversationDocumentsParams, type UseConversationDocumentsResult, type UseConversationListParams, type UseConversationListResult, type UseConversationMessagesResult, WINDOW_FILTERS, WelcomeFarewellForm, type WelcomeFarewellFormLabels, type WelcomeFarewellFormProps, WhatsAppCreateTemplateForm, type WhatsAppCreateTemplateFormLabels, type WhatsAppCreateTemplateFormProps, type WhatsAppCreateTemplateResult, type WhatsAppCreateTemplateState, WhatsAppMessageEditor, type WhatsAppMessageEditorProps, type WhatsAppTemplateHeaderType, WhatsAppTemplateSettingsForm, type WhatsAppTemplateSettingsFormLabels, type WhatsAppTemplateSettingsFormProps, type WhatsAppTemplateSummary, type WhatsAppTemplateVariableSuggestion, WhatsAppTemplatesSettings, type WhatsAppTemplatesSettingsLabels, type WhatsAppTemplatesSettingsProps, WindowExpiredNotice, type WindowExpiredNoticeLabels, type WindowExpiredNoticeProps, type WindowOfParams, buildTranscriptFilename, buildTranscriptText, downloadTextFile, formatFileSize, formatPhone, formatStalledFor, formatTimestamp, htmlToWA, isWindowBlocking, parseWhatsAppFormatting, phoneInitials, toast, useConversationContext, useConversationDocuments, useConversationList, useConversationLocales, useConversationMessages, useConversationRealtime, useConversations, useDarkMode, useGlobalRealtime, useIsDarkTheme, useIsNarrow, useToast, useWaitingNotifications, waToHTML, waToHTMLInline, windowOf };
1501
+ /**
1502
+ * Resolve a mídia de uma mensagem numa URL exibível, usando só o `ConversationsApi`.
1503
+ *
1504
+ * Mora no pacote, e não em cada host, porque a regra não tem nada de específico de produto: é a
1505
+ * tradução de `uploadId`/`mediaId` pelos dois métodos que o próprio contrato já declara. Deixá-la no
1506
+ * host significava que todo projeto que adotasse o SDK reescreveria as mesmas oito linhas — e, na
1507
+ * prática, ninguém escrevia: o `MediaRenderer` só busca mídia pela porta `onResolveMediaUrl`, então
1508
+ * onde nada era injetado foto, vídeo e áudio ficavam no placeholder para sempre.
1509
+ */
1510
+
1511
+ declare function createMediaUrlResolver(api: Pick<ConversationsApi, 'getDocumentUrl' | 'getMediaProxyUrl'>): ResolveMediaUrl;
1512
+
1513
+ /**
1514
+ * Textos da inbox. Todos sobrescrevíveis: o produto troca vocabulário ("cliente" vira "lead") ou
1515
+ * o idioma inteiro sem tocar no layout — e sem manter uma cópia da tela para isso.
1516
+ */
1517
+ interface ConversationsWorkspaceLabels {
1518
+ readonly title: string;
1519
+ readonly conversations: string;
1520
+ readonly waiting: string;
1521
+ readonly unread: string;
1522
+ readonly waitingOnly: string;
1523
+ readonly markSelectedAsRead: string;
1524
+ readonly search: string;
1525
+ readonly windowLegend: string;
1526
+ readonly channelLegend: string;
1527
+ readonly selectAll: string;
1528
+ readonly emptyList: string;
1529
+ readonly emptyDetail: string;
1530
+ readonly bulkSelected: (count: number) => string;
1531
+ readonly bulkClear: string;
1532
+ readonly bulkFinalize: string;
1533
+ readonly bulkFinalizeConfirm: (count: number) => string;
1534
+ readonly bulkTemplate: string;
1535
+ readonly markAllAsRead: string;
1536
+ readonly templateModalTitle: string;
1537
+ readonly templateModalSearch: string;
1538
+ readonly templateModalEmpty: string;
1539
+ readonly templateModalCancel: string;
1540
+ readonly templateModalSending: string;
1541
+ readonly templateModalNoneExpired: string;
1542
+ readonly templateModalAvailable: (count: number) => string;
1543
+ readonly templateModalSend: (count: number) => string;
1544
+ readonly messagesSelected: (count: number) => string;
1545
+ readonly copySelected: string;
1546
+ readonly composerPlaceholder: string;
1547
+ readonly attachFailure: string;
1548
+ /** Tira um arquivo da fila antes de enviar. */
1549
+ readonly attachmentRemove: string;
1550
+ readonly recordFailure: string;
1551
+ readonly sendFailure: string;
1552
+ readonly takeoverToReply: string;
1553
+ readonly signIn: string;
1554
+ readonly pageOf: (page: number, pageCount: number) => string;
1555
+ readonly rangeOf: (first: number, last: number, total: number) => string;
1556
+ }
1557
+ declare const DEFAULT_CONVERSATIONS_WORKSPACE_LABELS: ConversationsWorkspaceLabels;
1558
+
1559
+ /**
1560
+ * Estado da inbox: filtros, paginação, seleção em massa e ações de atendimento.
1561
+ *
1562
+ * Nasceu igual em três produtos e divergiu em três — contadores diferentes, um marcava lida ao
1563
+ * abrir e outro não, um perdia a página ao trocar de filtro. É a lógica de operar uma inbox, não
1564
+ * regra de nenhum negócio, e por isso mora aqui.
1565
+ *
1566
+ * A paginação é do cliente porque nem todo backend pagina a listagem. Fatiar aqui mantém a tela
1567
+ * utilizável com centenas de conversas; com dezenas de milhares o gargalo volta e a resposta é
1568
+ * paginar no servidor.
1569
+ */
1570
+
1571
+ declare const CONVERSATIONS_PER_PAGE = 50;
1572
+ interface UseConversationsInboxParams {
1573
+ /** Recortes do produto repassados crus ao backend dele (carteira, campanha, tipo). */
1574
+ readonly filters?: Record<string, string | undefined>;
1575
+ readonly perPage?: number;
1576
+ /**
1577
+ * Marca como lida a conversa aberta. Ligado por padrão: badge subindo na conversa que o atendente
1578
+ * tem na frente é ruído que ele não tem como resolver.
1579
+ */
1580
+ readonly markReadOnOpen?: boolean;
1581
+ /**
1582
+ * Pede a página ao servidor em vez de fatiar o que veio. Necessário quando a base é grande — o
1583
+ * padrão traz tudo e pagina no cliente porque nem todo backend pagina a listagem.
1584
+ */
1585
+ readonly serverPaginated?: boolean;
1586
+ readonly describeFailure?: (error: unknown) => string;
1587
+ }
1588
+ interface UseConversationsInboxResult {
1589
+ readonly conversations: readonly ConversationSummary[];
1590
+ readonly pageConversations: readonly ConversationSummary[];
1591
+ readonly selectedConversation: ConversationSummary | undefined;
1592
+ readonly loading: boolean;
1593
+ readonly now: number;
1594
+ readonly totalCount: number;
1595
+ readonly unreadCount: number;
1596
+ readonly waitingCount: number;
1597
+ readonly filteredCount: number;
1598
+ /** Selecionadas fora da janela de 24h — as únicas que um template alcança. */
1599
+ readonly expiredSelectedCount: number;
1600
+ readonly page: number;
1601
+ readonly pageCount: number;
1602
+ readonly firstOnPage: number;
1603
+ readonly lastOnPage: number;
1604
+ readonly selectedId: string | undefined;
1605
+ readonly selectedIds: ReadonlySet<string>;
1606
+ readonly allOnPageSelected: boolean;
1607
+ readonly waitingOnly: boolean;
1608
+ readonly windowFilter: ConversationWindow;
1609
+ readonly channelFilter: ChannelFilter;
1610
+ readonly channelFilters: readonly ChannelFilterOption[];
1611
+ readonly search: string;
1612
+ readonly busy: boolean;
1613
+ /** Por que a lista está vazia, quando não é por não haver conversa. */
1614
+ readonly loadFailure: string | undefined;
1615
+ /** Ausentes quando o host não implementa a capacidade — a UI não desenha a afordância. */
1616
+ readonly canTakeover: boolean;
1617
+ readonly canFinalize: boolean;
1618
+ readonly canListTemplates: boolean;
1619
+ readonly canMarkAllRead: boolean;
1620
+ refetch(): Promise<void> | void;
1621
+ selectConversation(conversationId: string): void;
1622
+ clearSelection(): void;
1623
+ toggleSelected(conversationId: string): void;
1624
+ toggleSelectAllOnPage(): void;
1625
+ clearBulkSelection(): void;
1626
+ setWaitingOnly(value: boolean): void;
1627
+ setWindowFilter(value: ConversationWindow): void;
1628
+ setChannelFilter(value: ChannelFilter): void;
1629
+ setSearch(value: string): void;
1630
+ goToPage(value: number): void;
1631
+ markSelectedAsRead(): Promise<void>;
1632
+ markAllAsRead(): Promise<void>;
1633
+ takeover(conversationId: string): Promise<void>;
1634
+ releaseToBot(conversationId: string): Promise<void>;
1635
+ finalize(conversationId: string): Promise<void>;
1636
+ finalizeSelected(): Promise<void>;
1637
+ sendTemplateToSelected(templateName?: string): Promise<void>;
1638
+ }
1639
+ declare function useConversationsInbox(params?: UseConversationsInboxParams): UseConversationsInboxResult;
1640
+
1641
+ interface ConversationsWorkspaceSimulator {
1642
+ /**
1643
+ * Desenha o painel do cliente. Fica com o host porque o simulador precisa da rota assinada no
1644
+ * servidor DELE — e é o que mantém o `preview/` fora do bundle de quem não usa.
1645
+ */
1646
+ render(params: {
1647
+ conversationId: string;
1648
+ close: () => void;
1649
+ }): ReactNode;
1650
+ /** Ausente = ligado. Serve para esconder fora de desenvolvimento sem condicionar o JSX. */
1651
+ readonly enabled?: boolean;
1652
+ /** Ícone da biblioteca (lucide) no utilitário do cabeçalho. Ausente, entra o frasco de teste. */
1653
+ readonly icon?: ReactNode;
1654
+ readonly label?: string;
1655
+ }
1656
+ interface ConversationsWorkspaceProps {
1657
+ readonly labels?: Partial<ConversationsWorkspaceLabels>;
1658
+ readonly filters?: Record<string, string | undefined>;
1659
+ readonly perPage?: number;
1660
+ readonly markReadOnOpen?: boolean;
1661
+ /** Pede a página ao servidor em vez de fatiar no cliente. */
1662
+ readonly serverPaginated?: boolean;
1663
+ /** Conversa a abrir na montagem (deep link `?id=`). */
1664
+ readonly initialConversationId?: string | undefined;
1665
+ /** Idem, pelo telefone — é o que costuma vir no link de um alerta ou de um pedido. */
1666
+ readonly initialWhatsappNumber?: string | undefined;
1667
+ readonly simulator?: ConversationsWorkspaceSimulator;
1668
+ readonly quickReplies?: readonly QuickReply[];
1669
+ readonly quickReplyVariablesFor?: (conversation: ConversationSummary, context: Record<string, unknown> | undefined) => Record<string, string>;
1670
+ /** Etapa do fluxo mostrada no painel de contexto. */
1671
+ readonly flowLabelOf?: (conversation: ConversationSummary) => string | undefined;
1672
+ /** Substitui o download local do transcript (ex.: exportação completa pela rota do servidor). */
1673
+ readonly onDownload?: (conversation: ConversationSummary) => void;
1674
+ /** Bloqueia o composer enquanto a conversa estiver com o bot. */
1675
+ readonly requireTakeoverToReply?: boolean;
1676
+ /** Deixa marcar mensagens no transcript e copiar o trecho. */
1677
+ readonly messageSelection?: boolean;
1678
+ /** Texto já no campo ao abrir a conversa (deep link que sugere a resposta). */
1679
+ readonly initialComposerText?: string | undefined;
1680
+ /** `rich` troca o campo simples pelo texto com a formatação do WhatsApp desenhada ao escrever. */
1681
+ readonly composer?: 'simple' | 'rich';
1682
+ /** Valores que o operador insere sem digitar. Só o composer `rich` os oferece. */
1683
+ readonly composerVariablesFor?: (conversation: ConversationSummary, context: Record<string, unknown> | undefined) => readonly RichComposerVariable[];
1684
+ /** Fila de anexos com legenda, como no WhatsApp. Ausente, o clipe manda cada arquivo na hora. */
1685
+ readonly onSendAttachments?: (conversation: ConversationSummary, files: readonly File[], caption: string) => Promise<void>;
1686
+ /** Nota de voz. Ausente, o microfone não aparece. */
1687
+ readonly onRecordAudio?: (conversation: ConversationSummary, file: File) => Promise<void>;
1688
+ readonly contextEntriesOf?: (context: Record<string, unknown> | undefined) => readonly ConversationContextEntry[];
1689
+ readonly onAttach?: (conversation: ConversationSummary, file: File) => Promise<void>;
1690
+ readonly extraUtilitiesFor?: (conversation: ConversationSummary) => readonly ConversationHeaderUtility[];
1691
+ readonly renderFilters?: (inbox: UseConversationsInboxResult) => ReactNode;
1692
+ readonly renderBulkActions?: (inbox: UseConversationsInboxResult) => ReactNode;
1693
+ readonly renderRow?: (conversation: ConversationSummary) => ReactNode;
1694
+ readonly renderAboveTranscript?: (conversation: ConversationSummary, context: Record<string, unknown> | undefined) => ReactNode;
1695
+ readonly renderHeaderActions?: (inbox: UseConversationsInboxResult) => ReactNode;
1696
+ readonly onSendTemplateToSelected?: (inbox: UseConversationsInboxResult) => void;
1697
+ /** Destino do link de reentrar no painel, mostrado junto do aviso de sessão expirada. */
1698
+ readonly signInHref?: string;
1699
+ readonly className?: string;
1700
+ }
1701
+ declare function ConversationsWorkspace({ labels: labelsOverride, filters, perPage, markReadOnOpen, serverPaginated, initialConversationId, initialWhatsappNumber, simulator, quickReplies, quickReplyVariablesFor, flowLabelOf, onDownload, requireTakeoverToReply, messageSelection, initialComposerText, composer, composerVariablesFor, onSendAttachments, onRecordAudio, contextEntriesOf, onAttach, extraUtilitiesFor, renderFilters, renderBulkActions, renderRow, renderAboveTranscript, renderHeaderActions, onSendTemplateToSelected, signInHref, className, }: ConversationsWorkspaceProps): react.JSX.Element;
1702
+
1703
+ interface ConversationPaneProps {
1704
+ readonly conversation: ConversationSummary;
1705
+ readonly now: number;
1706
+ readonly busy: boolean;
1707
+ readonly labels: ConversationsWorkspaceLabels;
1708
+ /** Devolve a promessa quando o host a tem: o envio de template espera a tomada antes de sair. */
1709
+ readonly onTakeover?: (() => void | Promise<void>) | undefined;
1710
+ readonly onReturnToBot?: (() => void) | undefined;
1711
+ readonly onFinish?: (() => void) | undefined;
1712
+ readonly onBack: () => void;
1713
+ readonly extraUtilities?: readonly ConversationHeaderUtility[];
1714
+ /** Traduz o contexto cru do produto nas linhas do painel. Ausente, o painel não aparece. */
1715
+ readonly contextEntriesOf?: (context: Record<string, unknown> | undefined) => readonly ConversationContextEntry[];
1716
+ readonly quickReplies?: readonly QuickReply[];
1717
+ /**
1718
+ * Recebe o contexto junto porque o dado que interessa à variável (o nome que o bot perguntou,
1719
+ * por exemplo) vive no contexto do fluxo, não no resumo da listagem.
1720
+ */
1721
+ readonly quickReplyVariablesFor?: (conversation: ConversationSummary, context: Record<string, unknown> | undefined) => Record<string, string>;
1722
+ /** Etapa do fluxo ao lado do contexto (ex.: "Anotando o pedido"). */
1723
+ readonly flowLabel?: string | undefined;
1724
+ /**
1725
+ * Substitui o download local do transcript. Existe para o produto que exporta pela rota do
1726
+ * servidor, onde o arquivo sai completo em vez de só com o que a tela carregou.
1727
+ */
1728
+ readonly onDownload?: (() => void) | undefined;
1729
+ /**
1730
+ * Bloqueia o composer enquanto a conversa estiver com o bot. Ligado, responder sem assumir
1731
+ * atropelaria o fluxo automático no meio de uma pergunta.
1732
+ */
1733
+ readonly requireTakeoverToReply?: boolean;
1734
+ /**
1735
+ * Deixa marcar mensagens e copiar o trecho. É o que se faz para levar um pedaço da conversa a um
1736
+ * e-mail ou a um chamado, sem baixar o transcript inteiro.
1737
+ */
1738
+ readonly messageSelection?: boolean;
1739
+ /** Texto já no campo ao abrir (deep link que sugere a resposta). */
1740
+ readonly initialComposerText?: string | undefined;
1741
+ /**
1742
+ * Peça do produto entre o contexto e o transcript (ex.: ficha do lead, resumo do pedido). Recebe o
1743
+ * contexto do fluxo junto: é dele que sai o resumo, e sem isso o host teria de buscá-lo de novo.
1744
+ */
1745
+ readonly renderAboveTranscript?: (conversation: ConversationSummary, context: Record<string, unknown> | undefined) => ReactNode;
1746
+ readonly onAttach?: ((file: File) => Promise<void>) | undefined;
1747
+ /**
1748
+ * `rich` troca o `textarea` pelo campo com a formatação do WhatsApp desenhada enquanto se escreve.
1749
+ * Vale onde o atendente manda texto longo e formatado; para responder "já vou ver" o campo simples
1750
+ * é menos coisa na tela.
1751
+ */
1752
+ readonly composer?: 'simple' | 'rich';
1753
+ /** Valores que o operador insere sem digitar. Só o composer `rich` os oferece. */
1754
+ readonly composerVariablesFor?: (conversation: ConversationSummary, context: Record<string, unknown> | undefined) => readonly RichComposerVariable[];
1755
+ /**
1756
+ * Fila de anexos com legenda, como no WhatsApp: os arquivos escolhidos ficam visíveis acima da
1757
+ * barra e saem junto com o texto escrito. Ausente, o clipe manda cada arquivo na hora — o que
1758
+ * perde a legenda, e era a diferença entre as telas.
1759
+ */
1760
+ readonly onSendAttachments?: (files: readonly File[], caption: string) => Promise<void>;
1761
+ /** Grava e envia nota de voz. Ausente, o microfone não aparece. */
1762
+ readonly onRecordAudio?: (file: File) => Promise<void>;
1763
+ }
1764
+ declare function ConversationPane({ conversation, now, busy, labels, onTakeover, onReturnToBot, onFinish, onBack, extraUtilities, contextEntriesOf, quickReplies, quickReplyVariablesFor, flowLabel, onDownload, requireTakeoverToReply, messageSelection, initialComposerText, renderAboveTranscript, onAttach, composer, composerVariablesFor, onSendAttachments, onRecordAudio, }: ConversationPaneProps): react.JSX.Element;
1765
+
1766
+ interface ConversationsInboxListProps {
1767
+ readonly inbox: UseConversationsInboxResult;
1768
+ readonly labels: ConversationsWorkspaceLabels;
1769
+ readonly className?: string;
1770
+ /** Barra extra do produto acima da lista (ex.: filtro de carteira, seletor de campanha). */
1771
+ readonly renderFilters?: (inbox: UseConversationsInboxResult) => ReactNode;
1772
+ /** Ações em lote do produto, ao lado de finalizar e template. */
1773
+ readonly renderBulkActions?: (inbox: UseConversationsInboxResult) => ReactNode;
1774
+ readonly renderRow?: (conversation: ConversationSummary) => ReactNode;
1775
+ readonly onSendTemplateToSelected?: () => void;
1776
+ }
1777
+ declare function ConversationsInboxList({ inbox, labels, className, renderFilters, renderBulkActions, renderRow, onSendTemplateToSelected, }: ConversationsInboxListProps): react.JSX.Element;
1778
+
1779
+ export { type AsyncResourceState, AudioPlayer, type AudioPlayerProps, AudioTranscription, type AudioTranscriptionProps, Avatar, type AvatarLabels, type AvatarProps, type BotMessages, type BuildTranscriptTextParams, BulkActionBar, type BulkActionBarProps, CHANNEL_BRAND_COLOR, CONVERSATIONS_PER_PAGE, CONVERSATION_WINDOW, ChannelFilter, ChannelFilterOption, ChannelIcon, type ChannelIconProps, ConversationChannel, type ConversationContextEntry, ConversationContextPanel, type ConversationContextPanelClassNames, type ConversationContextPanelLabels, type ConversationContextPanelProps, type ConversationContextStatus, ConversationDocument, ConversationDocumentsPanel, type ConversationDocumentsPanelClassNames, type ConversationDocumentsPanelLabels, type ConversationDocumentsPanelProps, ConversationHeader, type ConversationHeaderClassNames, type ConversationHeaderLabels, type ConversationHeaderProps, type ConversationHeaderUtility, ConversationListItem, type ConversationListItemLabels, type ConversationListItemProps, type ConversationLocales, ConversationLocalesProvider, type ConversationLocalesProviderProps, ConversationPane, type ConversationPaneProps, type ConversationRealtimeHandler, ConversationRow, type ConversationRowClassNames, type ConversationRowProps, ConversationSummary, ConversationTemplate, ConversationWallpaper, type ConversationWallpaperProps, type ConversationWindow, ConversationsApi, ConversationsFeatures, ConversationsInboxList, type ConversationsInboxListProps, ConversationsProvider, ConversationsWorkspace, type ConversationsWorkspaceLabels, type ConversationsWorkspaceProps, type ConversationsWorkspaceSimulator, DEFAULT_ACCEPTED_FILE_TYPES, DEFAULT_AVATAR_LABELS, DEFAULT_CONVERSATIONS_WORKSPACE_LABELS, DEFAULT_CONVERSATION_CONTEXT_LABELS, DEFAULT_CONVERSATION_DOCUMENTS_LABELS, DEFAULT_CONVERSATION_HEADER_LABELS, DEFAULT_CONVERSATION_LIST_ITEM_LABELS, DEFAULT_DOCUMENTS_LIBRARY_LABELS, DEFAULT_DOCUMENTS_WORKSPACE_LABELS, DEFAULT_EMOJI_PICKER_LABELS, DEFAULT_INTERACTIVE_MESSAGE_LABELS, DEFAULT_LIGHTBOX_LABELS, DEFAULT_MESSAGE_COMPOSER_LABELS, DEFAULT_RICH_COMPOSER_TOOLTIPS, DEFAULT_TEMPLATES_SETTINGS_LABELS, DEFAULT_WHATSAPP_MESSAGE_EDITOR_LABELS, DEFAULT_WINDOW_EXPIRED_LABELS, DOCUMENT_SOURCE_FILTER, DateDivider, type DateDividerClassNames, type DateDividerProps, type DocumentSourceFilter, type DocumentsFiltersContext, DocumentsLibrary, type DocumentsLibraryClassNames, type DocumentsLibraryLabels, type DocumentsLibraryProps, DocumentsWorkspace, type DocumentsWorkspaceClassNames, type DocumentsWorkspaceLabels, type DocumentsWorkspaceProps, EMOJI_CATEGORIES, type EmojiCategory, type EmojiEntry, EmojiPicker, type EmojiPickerLabels, type EmojiPickerProps, FileIcon, type FileIconProps, type FilterOption, InteractiveMessage, type InteractiveMessageLabels, type InteractiveMessageProps, InteractivePayload, InteractiveSelection, Lightbox, type LightboxLabels, type LightboxProps, ListConversationsParams, ListDocumentsParams, ListingPagination, type ListingPaginationProps, MessageBubble, type MessageBubbleProps, MessageComposer, type MessageComposerClassNames, type MessageComposerLabels, type MessageComposerProps, MessagePayload, MessageTail, MessageText, type MessageTextProps, MessageTimestamp, MessageTranscription, MessagesWorkspace, type MessagesWorkspaceApi, type MessagesWorkspaceLabels, type MessagesWorkspaceProps, MultiSelectFilter, type MultiSelectFilterProps, NARROW_MAX_WIDTH_PX, type QuickReply, RICH_COMPOSER_ACTION, ResolveMediaUrl, type RichComposerAction, type RichComposerQuickReply, type RichComposerTooltips, type RichComposerVariable, RichMessageComposer, type RichMessageComposerHandle, type RichMessageComposerProps, SSEProvider, SimpleEmojiPicker, type SimpleEmojiPickerProps, type SortDirection, SortableHead, type SortableHeadProps, StatusTicks, type StatusTicksProps, TEMPLATE_SETTINGS_TAB, TOOLTIP_ATTRIBUTE, type TemplateSettings, type TemplateSettingsTab, ToastProvider, TooltipLayer, type TopicItem, TopicsForm, type TopicsFormLabels, type TopicsFormProps, TranscriptionMode, type TranscriptionSettings, TranscriptionSettingsForm, type TranscriptionSettingsFormLabels, type TranscriptionSettingsFormProps, type UrlStateOptions, type UseConversationActionsResult, type UseConversationContextResult, type UseConversationDocumentsParams, type UseConversationDocumentsResult, type UseConversationListParams, type UseConversationListResult, type UseConversationMessagesResult, type UseConversationsInboxParams, type UseConversationsInboxResult, type UseInboxActionsResult, type UseScrollToLatestMessageParams, type UseScrollToLatestMessageResult, type UseWaitingNotificationsLabels, type UseWaitingNotificationsParams, type UseWaitingNotificationsResult, WINDOW_FILTERS, WelcomeFarewellForm, type WelcomeFarewellFormLabels, type WelcomeFarewellFormProps, WhatsAppCreateTemplateForm, type WhatsAppCreateTemplateFormLabels, type WhatsAppCreateTemplateFormProps, type WhatsAppCreateTemplateResult, type WhatsAppCreateTemplateState, WhatsAppMessageEditor, type WhatsAppMessageEditorLabels, type WhatsAppMessageEditorProps, type WhatsAppTemplateHeaderType, WhatsAppTemplateSettingsForm, type WhatsAppTemplateSettingsFormLabels, type WhatsAppTemplateSettingsFormProps, type WhatsAppTemplateSummary, type WhatsAppTemplateVariableSuggestion, WhatsAppTemplatesSettings, type WhatsAppTemplatesSettingsLabels, type WhatsAppTemplatesSettingsProps, WindowExpiredNotice, type WindowExpiredNoticeLabels, type WindowExpiredNoticeProps, type WindowOfParams, applyQuickReplyVariables, buildTranscriptFilename, buildTranscriptText, createMediaUrlResolver, downloadTextFile, formatDateTime, formatFileSize, formatPhone, formatStalledFor, formatTimestamp, htmlToWA, isSameDay, isWindowBlocking, parseWhatsAppFormatting, phoneInitials, resolveQuickReply, searchEmojis, toast, useConversationActions, useConversationContext, useConversationDocuments, useConversationList, useConversationLocales, useConversationMessages, useConversationRealtime, useConversations, useConversationsInbox, useDarkMode, useDebouncedValue, useGlobalRealtime, useInboxActions, useIsDarkTheme, useIsNarrow, useScrollToLatestMessage, useToast, useUrlArrayState, useUrlNumberState, useUrlStringState, useWaitingNotifications, waToHTML, waToHTMLInline, windowOf };