@adatechnology/conversations-ui 0.1.0-rc.2 → 0.1.0-rc.4
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-4R6Y43DQ.js +726 -0
- package/dist/chunk-NV2RZ5KT.js +56 -0
- package/dist/{chunk-ZDURDZTM.js → chunk-OGRRHQQW.js} +1 -41
- package/dist/flows/index.js +6 -4
- package/dist/index.d.ts +323 -111
- package/dist/index.js +1032 -954
- package/dist/preview/index.d.ts +172 -0
- package/dist/preview/index.js +576 -0
- package/dist/styles.css +198 -0
- package/dist/types-C0PtaO7S.d.ts +207 -0
- package/package.json +10 -3
- package/src/Avatar.tsx +18 -3
- package/src/ChannelIcon.tsx +87 -0
- package/src/ConversationContextPanel.tsx +106 -0
- package/src/ConversationDocumentsPanel.tsx +107 -0
- package/src/ConversationHeader.tsx +239 -0
- package/src/ConversationListItem.tsx +36 -5
- package/src/ConversationLocalesProvider.tsx +16 -0
- package/src/ConversationRow.tsx +137 -0
- package/src/DateDivider.tsx +16 -3
- package/src/MediaRenderer.tsx +9 -9
- package/src/MessageBubble.tsx +24 -2
- package/src/MessageComposer.tsx +15 -2
- package/src/Wallpaper.tsx +4 -2
- package/src/WindowExpiredNotice.tsx +57 -0
- package/src/conversationChannel.test.ts +53 -0
- package/src/conversationChannel.ts +146 -0
- package/src/conversationTranscript.test.ts +65 -0
- package/src/conversationTranscript.ts +64 -0
- package/src/conversationWindow.test.ts +90 -0
- package/src/conversationWindow.ts +78 -0
- package/src/flows/FlowMapCanvas.tsx +2 -2
- package/src/hooks/useConversationDocuments.ts +4 -2
- package/src/index.ts +73 -4
- package/src/lib/cn.ts +15 -0
- package/src/lib/phone.ts +34 -0
- package/src/preview/ConversationPreview.tsx +148 -0
- package/src/preview/createMockConversationsApi.ts +111 -0
- package/src/preview/createMockSSEProvider.ts +40 -0
- package/src/preview/createPreviewWebhookClient.test.ts +105 -0
- package/src/preview/createPreviewWebhookClient.ts +99 -0
- package/src/preview/index.ts +40 -0
- package/src/preview/mockEventSource.ts +53 -0
- package/src/preview/preview.test.ts +175 -0
- package/src/preview/previewFixtures.ts +153 -0
- package/src/preview/previewStore.ts +193 -0
- package/src/preview/startPreviewScript.ts +60 -0
- package/src/providers/types.ts +36 -2
- package/src/settings/WhatsAppTemplatesSettings.tsx +106 -0
- package/src/styles.css +136 -0
- package/src/types.ts +8 -0
- package/src/useDarkMode.ts +26 -0
- package/src/useIsNarrow.ts +29 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { M as MessagePayload, i as ConversationSummary, h as ConversationEventSource, j as ConversationsApi, S as SSEProvider } from '../types-C0PtaO7S.js';
|
|
2
|
+
import * as react from 'react';
|
|
3
|
+
import { InteractiveReplyOption } from '@adatechnology/meta-whatsapp-contracts/testing';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Estado em memória que alimenta o preview de atendimento humano. Mock de API e mock de SSE
|
|
7
|
+
* compartilham este store de propósito: se cada um tivesse dados próprios, um evento anunciaria
|
|
8
|
+
* mensagem nova e o refetch da lista devolveria o estado antigo — a inbox pareceria funcionar e
|
|
9
|
+
* estaria mentindo, que é exatamente o defeito que o preview deveria expor.
|
|
10
|
+
*
|
|
11
|
+
* Os nomes de canal e de evento espelham o servidor (`conv:<whatsappNumber>`, `global`,
|
|
12
|
+
* `message`/`message-status`/`mode-changed`/`data-changed`). Fidelidade de vocabulário é o que
|
|
13
|
+
* permite trocar mock por servidor real sem tocar na UI.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
declare const GLOBAL_CHANNEL = "global";
|
|
17
|
+
declare function conversationChannel(conversationId: string): string;
|
|
18
|
+
type PreviewEmission = {
|
|
19
|
+
readonly channel: string;
|
|
20
|
+
readonly event: string;
|
|
21
|
+
readonly payload: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
type PreviewStoreListener = (emission: PreviewEmission) => void;
|
|
24
|
+
type AppendMessageParams = {
|
|
25
|
+
readonly conversationId: string;
|
|
26
|
+
readonly content: string;
|
|
27
|
+
readonly direction: MessagePayload['direction'];
|
|
28
|
+
readonly sender: MessagePayload['sender'];
|
|
29
|
+
};
|
|
30
|
+
type SetModeParams = {
|
|
31
|
+
readonly conversationId: string;
|
|
32
|
+
readonly mode: ConversationSummary['mode'];
|
|
33
|
+
readonly assignedUserId?: string | undefined;
|
|
34
|
+
};
|
|
35
|
+
type ListConversationsFilters = {
|
|
36
|
+
readonly waitingHuman?: boolean;
|
|
37
|
+
readonly search?: string;
|
|
38
|
+
};
|
|
39
|
+
type PreviewStore = {
|
|
40
|
+
listConversations(filters?: ListConversationsFilters): ConversationSummary[];
|
|
41
|
+
listMessages(conversationId: string): MessagePayload[];
|
|
42
|
+
appendMessage(params: AppendMessageParams): MessagePayload;
|
|
43
|
+
setMode(params: SetModeParams): void;
|
|
44
|
+
requestHuman(conversationId: string): void;
|
|
45
|
+
markRead(conversationId: string): void;
|
|
46
|
+
subscribe(channel: string, listener: PreviewStoreListener): () => void;
|
|
47
|
+
};
|
|
48
|
+
type CreatePreviewStoreParams = {
|
|
49
|
+
readonly conversations: readonly ConversationSummary[];
|
|
50
|
+
readonly messages: Readonly<Record<string, readonly MessagePayload[]>>;
|
|
51
|
+
readonly now?: () => Date;
|
|
52
|
+
};
|
|
53
|
+
declare function createPreviewStore(params: CreatePreviewStoreParams): PreviewStore;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `EventSource` só existe com um servidor HTTP do outro lado — é justamente o que falta quando se
|
|
57
|
+
* quer a inbox rodando com dados mockados. Este é o objeto mínimo que satisfaz
|
|
58
|
+
* `ConversationEventSource`: assina eventos nomeados, desassina e fecha.
|
|
59
|
+
*
|
|
60
|
+
* Não imita `EventSource` por completo de propósito: um fake "quase real" convida a depender de
|
|
61
|
+
* membros que o pacote não usa, e passa a quebrar a cada mudança de runtime.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
type MockEventSource = ConversationEventSource & {
|
|
65
|
+
emit(event: string, payload: unknown): void;
|
|
66
|
+
readonly closed: boolean;
|
|
67
|
+
};
|
|
68
|
+
declare function createMockEventSource(): MockEventSource;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `ConversationsApi` servido pelo store em memória. Como o pacote é headless e recebe a API por
|
|
72
|
+
* injeção, o preview de atendimento humano não precisa de servidor, banco nem Meta: é só outra
|
|
73
|
+
* implementação deste mesmo contrato.
|
|
74
|
+
*
|
|
75
|
+
* Toda resposta é assíncrona e passa por um atraso configurável — API instantânea esconde estados
|
|
76
|
+
* de carregamento, e é neles que a inbox costuma mostrar defeito.
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
type CreateMockConversationsApiParams = {
|
|
80
|
+
readonly store: PreviewStore;
|
|
81
|
+
readonly latencyMs?: number;
|
|
82
|
+
readonly agentName?: string;
|
|
83
|
+
};
|
|
84
|
+
declare function createMockConversationsApi(params: CreateMockConversationsApiParams): ConversationsApi;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* `SSEProvider` servido pelo store em memória. Mesmo mapeamento de canal do servidor
|
|
88
|
+
* (`conv:<conversationId>` e `global`), para que a UI não perceba a troca.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
type CreateMockSSEProviderParams = {
|
|
92
|
+
readonly store: PreviewStore;
|
|
93
|
+
};
|
|
94
|
+
declare function createMockSSEProvider(params: CreateMockSSEProviderParams): SSEProvider;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Conversas de partida do preview. Cobrem o espaço de estados que a inbox precisa saber desenhar —
|
|
98
|
+
* bot em atendimento, cliente esperando humano, conversa já assumida por atendente, conversa com
|
|
99
|
+
* áudio — porque estado que não aparece em fixture é estado que ninguém testa.
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
declare const PREVIEW_CONVERSATIONS: readonly ConversationSummary[];
|
|
103
|
+
declare const PREVIEW_MESSAGES: Readonly<Record<string, readonly MessagePayload[]>>;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Cliente que entrega mensagens do preview no webhook real, assinadas com HMAC — a mesma validação
|
|
107
|
+
* de staging e produção, sem rota alternativa e sem bypass. Do ponto de vista da API, este cliente
|
|
108
|
+
* é indistinguível da Meta; o que muda é apenas quem assina.
|
|
109
|
+
*
|
|
110
|
+
* Assina com WebCrypto porque `node:crypto` não existe no navegador. Os builders vêm dos contratos
|
|
111
|
+
* (isomórficos) justamente para que o mesmo payload seja montado nos dois runtimes.
|
|
112
|
+
*
|
|
113
|
+
* ⚠️ Isto carrega o app secret de DESENVOLVIMENTO no bundle. Só existe para o docker local, e
|
|
114
|
+
* `assertPreviewEnvironment` recusa rodar em produção — um segredo de dev vazado é irrelevante,
|
|
115
|
+
* mas o hábito de embarcar segredo em frontend não é.
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
type PreviewWebhookClient = {
|
|
119
|
+
sendText(text: string): Promise<void>;
|
|
120
|
+
sendButtonReply(reply: InteractiveReplyOption): Promise<void>;
|
|
121
|
+
sendListReply(reply: InteractiveReplyOption): Promise<void>;
|
|
122
|
+
sendAudio(mediaId: string): Promise<void>;
|
|
123
|
+
};
|
|
124
|
+
type CreatePreviewWebhookClientParams = {
|
|
125
|
+
readonly webhookUrl: string;
|
|
126
|
+
readonly appSecret: string;
|
|
127
|
+
readonly from: string;
|
|
128
|
+
readonly phoneNumberId?: string;
|
|
129
|
+
readonly fetchImplementation?: typeof fetch;
|
|
130
|
+
};
|
|
131
|
+
declare class PreviewInProductionError extends Error {
|
|
132
|
+
constructor();
|
|
133
|
+
}
|
|
134
|
+
declare class PreviewWebhookRejectedError extends Error {
|
|
135
|
+
readonly status: number;
|
|
136
|
+
constructor(status: number);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Falha alto em vez de degradar em silêncio: um preview que "quase funciona" em produção é pior
|
|
140
|
+
* que um que se recusa a montar.
|
|
141
|
+
*/
|
|
142
|
+
declare function assertPreviewEnvironment(isProduction: boolean): void;
|
|
143
|
+
declare function createPreviewWebhookClient(params: CreatePreviewWebhookClientParams): PreviewWebhookClient;
|
|
144
|
+
|
|
145
|
+
type ConversationPreviewProps = {
|
|
146
|
+
client: PreviewWebhookClient;
|
|
147
|
+
sse: SSEProvider;
|
|
148
|
+
conversationId: string;
|
|
149
|
+
loadMessages: (conversationId: string) => Promise<MessagePayload[]>;
|
|
150
|
+
placeholder?: string;
|
|
151
|
+
};
|
|
152
|
+
declare function ConversationPreview({ client, sse, conversationId, loadMessages, placeholder, }: ConversationPreviewProps): react.JSX.Element;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Roteiro que mantém o preview vivo: sem tráfego chegando, a inbox é uma tela estática e as
|
|
156
|
+
* transições que o atendente precisa testar (fila de espera enchendo, handoff, devolução ao bot)
|
|
157
|
+
* nunca acontecem.
|
|
158
|
+
*
|
|
159
|
+
* O roteiro é cíclico e determinístico — mesma ordem a cada execução. Aleatoriedade tornaria um
|
|
160
|
+
* defeito visto uma vez difícil de reencontrar.
|
|
161
|
+
*/
|
|
162
|
+
|
|
163
|
+
type PreviewScriptStep = (store: PreviewStore) => void;
|
|
164
|
+
declare const DEFAULT_PREVIEW_SCRIPT: readonly PreviewScriptStep[];
|
|
165
|
+
type StartPreviewScriptParams = {
|
|
166
|
+
readonly store: PreviewStore;
|
|
167
|
+
readonly intervalMs?: number;
|
|
168
|
+
readonly steps?: readonly PreviewScriptStep[];
|
|
169
|
+
};
|
|
170
|
+
declare function startPreviewScript(params: StartPreviewScriptParams): () => void;
|
|
171
|
+
|
|
172
|
+
export { type AppendMessageParams, ConversationPreview, type ConversationPreviewProps, type CreateMockConversationsApiParams, type CreateMockSSEProviderParams, type CreatePreviewStoreParams, type CreatePreviewWebhookClientParams, DEFAULT_PREVIEW_SCRIPT, GLOBAL_CHANNEL, type ListConversationsFilters, type MockEventSource, PREVIEW_CONVERSATIONS, PREVIEW_MESSAGES, type PreviewEmission, PreviewInProductionError, type PreviewScriptStep, type PreviewStore, type PreviewStoreListener, type PreviewWebhookClient, PreviewWebhookRejectedError, type SetModeParams, type StartPreviewScriptParams, assertPreviewEnvironment, conversationChannel, createMockConversationsApi, createMockEventSource, createMockSSEProvider, createPreviewStore, createPreviewWebhookClient, startPreviewScript };
|