@developer.notchatbot/webchat 1.5.3 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/config/endpoints.d.ts +9 -0
- package/dist/types.d.ts +33 -0
- package/dist/utils/convex.d.ts +3 -2
- package/dist/utils/survey.d.ts +30 -0
- package/dist/webchat-bundle.min.js +3251 -3169
- package/dist/webchat-bundle.min.umd.cjs +33 -33
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,8 @@ interface WebChatConfig {
|
|
|
44
44
|
active?: boolean; // Enable or disable the button (default: true)
|
|
45
45
|
color?: string; // Customize the internal WhatsApp button color
|
|
46
46
|
};
|
|
47
|
+
apiBaseUrl?: string; // Backend override (see "Targeting a non-production backend")
|
|
48
|
+
realtimeUrl?: string; // Convex deployment override (same section)
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
interface WebChatPositionConfig {
|
|
@@ -85,6 +87,33 @@ WebChat.initialize({
|
|
|
85
87
|
});
|
|
86
88
|
```
|
|
87
89
|
|
|
90
|
+
## 🎯 Targeting a non-production backend
|
|
91
|
+
|
|
92
|
+
By default the widget picks its backend from the hostname of the page it runs
|
|
93
|
+
on: `localhost` → `http://localhost:3000`, anything else → production
|
|
94
|
+
(`https://next.notchatbot.com`). That default is right for a merchant's
|
|
95
|
+
storefront, but wrong wherever the page itself is a non-production deployment —
|
|
96
|
+
a Vercel preview, `dev.notchatbot.com`, or a local dev server on a port other
|
|
97
|
+
than 3000. Without an override, a message typed on a preview lands in the
|
|
98
|
+
**production** inbox.
|
|
99
|
+
|
|
100
|
+
`apiBaseUrl` and `realtimeUrl` override that detection:
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
WebChat.initialize({
|
|
104
|
+
apiKey: "your-chatbot-uid",
|
|
105
|
+
apiBaseUrl: window.location.origin, // HTTP: /api/webchat, /upload, /rate
|
|
106
|
+
realtimeUrl: "https://<deployment>.convex.cloud" // Convex realtime subscriptions
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- Both must be `https://` (or `http://localhost` / `http://127.0.0.1`); anything
|
|
111
|
+
else is ignored with a console warning and the defaults are kept.
|
|
112
|
+
- **Set them as a pair.** `apiBaseUrl` alone writes to one deployment while the
|
|
113
|
+
widget keeps listening on the default Convex, so agent replies never arrive.
|
|
114
|
+
- Omitting them keeps the previous behaviour exactly — existing embeds are
|
|
115
|
+
unaffected, and each `initialize()` clears any override from a prior call.
|
|
116
|
+
|
|
88
117
|
# 💬 WhatsApp Button
|
|
89
118
|
|
|
90
119
|
If you simply want a floating WhatsApp action button with no WebChat, you can use `WhatsAppButtonAPI`, which isolates itself in the Shadow DOM to avoid CSS conflicts.
|
|
@@ -5,6 +5,15 @@ export interface EndpointConfig {
|
|
|
5
5
|
rateEndpoint: string;
|
|
6
6
|
realtimeUrl: string;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Replaces the endpoint overrides. Called on every `initialize()`, so a config
|
|
10
|
+
* without these keys clears any previous override. Invalid URLs are ignored
|
|
11
|
+
* with a warning and the environment defaults are kept.
|
|
12
|
+
*/
|
|
13
|
+
export declare function setEndpointOverrides(overrides: {
|
|
14
|
+
apiBaseUrl?: string;
|
|
15
|
+
realtimeUrl?: string;
|
|
16
|
+
}): void;
|
|
8
17
|
/**
|
|
9
18
|
* Detecta si estamos en ambiente de desarrollo
|
|
10
19
|
*/
|
package/dist/types.d.ts
CHANGED
|
@@ -25,6 +25,22 @@ export interface WebChatConfig {
|
|
|
25
25
|
whatsapp?: Omit<WhatsAppConfig, 'position' | 'marginBottom' | 'marginSide' | 'mobile' | 'desktop'> & {
|
|
26
26
|
active?: boolean;
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Optional backend base URL override (e.g. a Vercel preview deployment or
|
|
30
|
+
* dev.notchatbot.com). `/api/webchat`, `/api/webchat/upload` and
|
|
31
|
+
* `/api/webchat/conversation/rate` are derived from it. Must be https://
|
|
32
|
+
* (or http://localhost). Omitted or invalid → the environment defaults.
|
|
33
|
+
*/
|
|
34
|
+
apiBaseUrl?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional Convex deployment URL override for the realtime subscriptions
|
|
37
|
+
* (agent replies, history, activation). Must be https:// (or
|
|
38
|
+
* http://localhost). Omitted or invalid → the environment default.
|
|
39
|
+
*
|
|
40
|
+
* Pair it with `apiBaseUrl`: pointing HTTP at one deployment and realtime at
|
|
41
|
+
* another means the widget writes to one database and listens on another.
|
|
42
|
+
*/
|
|
43
|
+
realtimeUrl?: string;
|
|
28
44
|
/**
|
|
29
45
|
* Optional GTM/GA event name overrides for dataLayer pushes.
|
|
30
46
|
* If omitted, defaults are used.
|
|
@@ -142,6 +158,15 @@ export interface ChatWindowProps {
|
|
|
142
158
|
isRated?: boolean;
|
|
143
159
|
onRatingChange?: (isRated: boolean) => void;
|
|
144
160
|
conversationId?: string;
|
|
161
|
+
/** Configurable auto-survey threshold from the backend; undefined = legacy default (2). */
|
|
162
|
+
surveyAfterUserMessages?: number;
|
|
163
|
+
/** Timestamp of the last manual survey request from Livechat; undefined = never requested. */
|
|
164
|
+
webchatSurveyRequestedAt?: number;
|
|
165
|
+
}
|
|
166
|
+
/** Survey-related conversation state forwarded from the Convex realtime subscription. */
|
|
167
|
+
export interface ConversationSurveyState {
|
|
168
|
+
surveyAfterUserMessages?: number;
|
|
169
|
+
webchatSurveyRequestedAt?: number;
|
|
145
170
|
}
|
|
146
171
|
export interface ChatHeaderProps {
|
|
147
172
|
title: string;
|
|
@@ -195,8 +220,16 @@ export interface WebChatInstance {
|
|
|
195
220
|
setIsOpen?: (open: boolean) => void;
|
|
196
221
|
updateConfig?: (newConfig: Partial<WebChatConfig>) => void;
|
|
197
222
|
setPosition?: (pos: Partial<WebChatConfig>) => void;
|
|
223
|
+
getIsOpen?: () => boolean;
|
|
198
224
|
hide?: () => void;
|
|
199
225
|
show?: () => void;
|
|
226
|
+
/**
|
|
227
|
+
* Starts a new conversation in place: new conversation id, empty transcript,
|
|
228
|
+
* fresh visitor session, realtime subscriptions reopened. Unlike calling
|
|
229
|
+
* `initialize()` again it does not destroy and rebuild the widget, so the
|
|
230
|
+
* panel does not blink out while the new thread is prepared.
|
|
231
|
+
*/
|
|
232
|
+
restartConversation?: () => void;
|
|
200
233
|
injectCSS?: (css: string) => void;
|
|
201
234
|
removeCustomCSS?: () => void;
|
|
202
235
|
}
|
package/dist/utils/convex.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConvexReactClient } from 'convex/react';
|
|
2
|
-
import { Message } from '../types';
|
|
2
|
+
import { ConversationSurveyState, Message } from '../types';
|
|
3
3
|
export interface ConvexConnectionData {
|
|
4
4
|
client: ConvexReactClient;
|
|
5
5
|
unsubscribe: (() => void) | null;
|
|
@@ -11,9 +11,10 @@ export interface ConvexConnectionData {
|
|
|
11
11
|
* @param conversationId Conversation ID
|
|
12
12
|
* @param onMessage Callback for new messages
|
|
13
13
|
* @param onChatbotToggle Callback for chatbot activation changes
|
|
14
|
+
* @param onSurveyStateChange Callback for survey state changes (threshold + manual trigger)
|
|
14
15
|
* @returns Promise that resolves to Convex connection data
|
|
15
16
|
*/
|
|
16
|
-
export declare const initializeConvexConnection: (realtimeEndpoint: string, _chatbotUid: string, conversationId: string, onMessage: (message: Message) => void, onChatbotToggle?: (chatbotActivated: boolean) => void) => Promise<ConvexConnectionData>;
|
|
17
|
+
export declare const initializeConvexConnection: (realtimeEndpoint: string, _chatbotUid: string, conversationId: string, onMessage: (message: Message) => void, onChatbotToggle?: (chatbotActivated: boolean) => void, onSurveyStateChange?: (surveyState: ConversationSurveyState) => void) => Promise<ConvexConnectionData>;
|
|
17
18
|
/**
|
|
18
19
|
* Fetches initial conversation data with messages from Convex
|
|
19
20
|
* @param realtimeEndpoint Realtime service deployment URL
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Message } from '../types';
|
|
2
|
+
/** Legacy hardcoded threshold, used when the backend does not send one. */
|
|
3
|
+
export declare const DEFAULT_SURVEY_AFTER_USER_MESSAGES = 2;
|
|
4
|
+
/**
|
|
5
|
+
* Resolves the configured auto-survey threshold.
|
|
6
|
+
* Falls back to the default when the backend does not expose the field yet
|
|
7
|
+
* or sends something unusable (non-number, NaN, zero/negative).
|
|
8
|
+
*/
|
|
9
|
+
export declare const resolveSurveyThreshold: (value: unknown) => number;
|
|
10
|
+
/** Counts only messages sent by the end user (bot/employee ones don't count). */
|
|
11
|
+
export declare const countUserMessages: (messages: Message[]) => number;
|
|
12
|
+
/**
|
|
13
|
+
* Whether the survey should auto-open because the user reached the
|
|
14
|
+
* configured message threshold. Never true for already rated conversations.
|
|
15
|
+
*/
|
|
16
|
+
export declare const shouldAutoShowSurvey: (messages: Message[], surveyAfterUserMessages: number | undefined, isRated: boolean) => boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Whether a manual survey request (`webchatSurveyRequestedAt`, a timestamp
|
|
19
|
+
* written by an agent from Livechat) is a new, still unhandled trigger.
|
|
20
|
+
* Comparing against the last handled value — not just presence — keeps
|
|
21
|
+
* re-renders and Convex reconnections from re-opening the survey for the
|
|
22
|
+
* same request, while a fresh timestamp triggers it again.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately NOT gated on `isRated`: a manual request fired after a rating
|
|
25
|
+
* re-opens the survey so the agent can re-validate the experience (the new
|
|
26
|
+
* rating overwrites the previous one server-side). Stale requests can't leak
|
|
27
|
+
* across reloads because the backend clears `webchatSurveyRequestedAt` when a
|
|
28
|
+
* rating is submitted — a present timestamp is always a pending ask.
|
|
29
|
+
*/
|
|
30
|
+
export declare const isNewSurveyRequest: (requestedAt: number | undefined, lastHandledRequestedAt: number | undefined) => boolean;
|