@yext/chat-ui-react 0.10.0 → 0.10.2
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/lib/commonjs/package.json.js +1 -1
- package/lib/commonjs/src/components/ChatInput.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatInput.js +9 -2
- package/lib/commonjs/src/components/ChatInput.js.map +1 -1
- package/lib/commonjs/src/components/ChatPanel.d.ts +4 -0
- package/lib/commonjs/src/components/ChatPanel.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatPanel.js +5 -5
- package/lib/commonjs/src/components/ChatPanel.js.map +1 -1
- package/lib/commonjs/src/components/ChatPopUp.d.ts.map +1 -1
- package/lib/commonjs/src/components/ChatPopUp.js +4 -2
- package/lib/commonjs/src/components/ChatPopUp.js.map +1 -1
- package/lib/commonjs/src/components/Markdown.d.ts +3 -1
- package/lib/commonjs/src/components/Markdown.d.ts.map +1 -1
- package/lib/commonjs/src/components/Markdown.js +3 -2
- package/lib/commonjs/src/components/Markdown.js.map +1 -1
- package/lib/commonjs/src/components/MessageBubble.d.ts +3 -1
- package/lib/commonjs/src/components/MessageBubble.d.ts.map +1 -1
- package/lib/commonjs/src/components/MessageBubble.js +2 -2
- package/lib/commonjs/src/components/MessageBubble.js.map +1 -1
- package/lib/commonjs/src/components/MessageSuggestions.d.ts.map +1 -1
- package/lib/commonjs/src/components/MessageSuggestions.js +8 -1
- package/lib/commonjs/src/components/MessageSuggestions.js.map +1 -1
- package/lib/commonjs/src/hooks/useFetchInitialMessage.d.ts.map +1 -1
- package/lib/commonjs/src/hooks/useFetchInitialMessage.js +9 -1
- package/lib/commonjs/src/hooks/useFetchInitialMessage.js.map +1 -1
- package/lib/commonjs/src/hooks/useSendMessageWithRetries.d.ts.map +1 -1
- package/lib/commonjs/src/hooks/useSendMessageWithRetries.js +3 -1
- package/lib/commonjs/src/hooks/useSendMessageWithRetries.js.map +1 -1
- package/lib/esm/index.d.ts +7 -1
- package/lib/esm/package.json.mjs +1 -1
- package/lib/esm/src/components/ChatInput.d.ts.map +1 -1
- package/lib/esm/src/components/ChatInput.mjs +9 -2
- package/lib/esm/src/components/ChatInput.mjs.map +1 -1
- package/lib/esm/src/components/ChatPanel.d.ts +4 -0
- package/lib/esm/src/components/ChatPanel.d.ts.map +1 -1
- package/lib/esm/src/components/ChatPanel.mjs +5 -5
- package/lib/esm/src/components/ChatPanel.mjs.map +1 -1
- package/lib/esm/src/components/ChatPopUp.d.ts.map +1 -1
- package/lib/esm/src/components/ChatPopUp.mjs +4 -2
- package/lib/esm/src/components/ChatPopUp.mjs.map +1 -1
- package/lib/esm/src/components/Markdown.d.ts +3 -1
- package/lib/esm/src/components/Markdown.d.ts.map +1 -1
- package/lib/esm/src/components/Markdown.mjs +3 -2
- package/lib/esm/src/components/Markdown.mjs.map +1 -1
- package/lib/esm/src/components/MessageBubble.d.ts +3 -1
- package/lib/esm/src/components/MessageBubble.d.ts.map +1 -1
- package/lib/esm/src/components/MessageBubble.mjs +2 -2
- package/lib/esm/src/components/MessageBubble.mjs.map +1 -1
- package/lib/esm/src/components/MessageSuggestions.d.ts.map +1 -1
- package/lib/esm/src/components/MessageSuggestions.mjs +8 -1
- package/lib/esm/src/components/MessageSuggestions.mjs.map +1 -1
- package/lib/esm/src/hooks/useFetchInitialMessage.d.ts.map +1 -1
- package/lib/esm/src/hooks/useFetchInitialMessage.mjs +9 -1
- package/lib/esm/src/hooks/useFetchInitialMessage.mjs.map +1 -1
- package/lib/esm/src/hooks/useSendMessageWithRetries.d.ts.map +1 -1
- package/lib/esm/src/hooks/useSendMessageWithRetries.mjs +3 -1
- package/lib/esm/src/hooks/useSendMessageWithRetries.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/ChatInput.tsx +16 -7
- package/src/components/ChatPanel.tsx +33 -14
- package/src/components/ChatPopUp.tsx +4 -3
- package/src/components/Markdown.tsx +5 -1
- package/src/components/MessageBubble.tsx +4 -0
- package/src/components/MessageSuggestions.tsx +12 -5
- package/src/hooks/useFetchInitialMessage.ts +11 -3
- package/src/hooks/useSendMessageWithRetries.ts +34 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFetchInitialMessage.mjs","sources":["../../../../src/hooks/useFetchInitialMessage.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\n\n/**\n * Sends a request to Chat API to fetch the initial message when the\n * conversation first start or when the message history is reset.\n *\n * @internal\n *\n * @param handleError - A function which is called when an error occurs while fetching for initial message.\n * By default, the error is logged to the console and an error message is added to state.\n * @param stream - Enable streaming behavior by making a request to Chat Streaming API. Defaults to false.\n * @param customCondition - additional condition for when to fetch initial message\n */\nexport function useFetchInitialMessage(\n handleError?: (e: unknown) => void,\n stream = false,\n customCondition = true
|
|
1
|
+
{"version":3,"file":"useFetchInitialMessage.mjs","sources":["../../../../src/hooks/useFetchInitialMessage.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useChatState, useChatActions } from \"@yext/chat-headless-react\";\nimport { useDefaultHandleApiError } from \"../hooks/useDefaultHandleApiError\";\n\n/**\n * Sends a request to Chat API to fetch the initial message when the\n * conversation first start or when the message history is reset.\n *\n * @internal\n *\n * @param handleError - A function which is called when an error occurs while fetching for initial message.\n * By default, the error is logged to the console and an error message is added to state.\n * @param stream - Enable streaming behavior by making a request to Chat Streaming API. Defaults to false.\n * @param customCondition - additional condition for when to fetch initial message\n */\nexport function useFetchInitialMessage(\n handleError?: (e: unknown) => void,\n stream = false,\n customCondition = true\n) {\n const chat = useChatActions();\n const defaultHandleApiError = useDefaultHandleApiError();\n const messages = useChatState((state) => state.conversation.messages);\n const canSendMessage = useChatState(\n (state) => state.conversation.canSendMessage\n );\n\n useEffect(() => {\n if (messages.length !== 0 || !canSendMessage || !customCondition) {\n return;\n }\n const res = stream ? chat.streamNextMessage() : chat.getNextMessage();\n res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));\n }, [\n chat,\n stream,\n handleError,\n defaultHandleApiError,\n canSendMessage,\n customCondition,\n messages.length,\n ]);\n}\n"],"names":[],"mappings":";;;;AAIA;;;;;;;;;;AAUG;AACG,SAAU,sBAAsB,CACpC,WAAkC,EAClC,MAAM,GAAG,KAAK,EACd,eAAe,GAAG,IAAI,EAAA;AAEtB,IAAA,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;AAC9B,IAAA,MAAM,qBAAqB,GAAG,wBAAwB,EAAE,CAAC;AACzD,IAAA,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;AACtE,IAAA,MAAM,cAAc,GAAG,YAAY,CACjC,CAAC,KAAK,KAAK,KAAK,CAAC,YAAY,CAAC,cAAc,CAC7C,CAAC;IAEF,SAAS,CAAC,MAAK;QACb,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,eAAe,EAAE;YAChE,OAAO;AACR,SAAA;AACD,QAAA,MAAM,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QACtE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9E,KAAC,EAAE;QACD,IAAI;QACJ,MAAM;QACN,WAAW;QACX,qBAAqB;QACrB,cAAc;QACd,eAAe;AACf,QAAA,QAAQ,CAAC,MAAM;AAChB,KAAA,CAAC,CAAC;AACL;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSendMessageWithRetries.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useSendMessageWithRetries.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,UAAQ,EACd,UAAU,SAAI,EACd,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,GAC7B,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"useSendMessageWithRetries.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useSendMessageWithRetries.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,UAAQ,EACd,UAAU,SAAI,EACd,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,GAC7B,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAiClC"}
|
|
@@ -23,7 +23,9 @@ function useSendMessageWithRetries(stream = false, maxRetries = 0, onRetry) {
|
|
|
23
23
|
let text = input;
|
|
24
24
|
for (let numRetries = 0; numRetries <= maxRetries; numRetries++) {
|
|
25
25
|
if (numRetries > 0 && !!err) {
|
|
26
|
-
if (err instanceof ApiError &&
|
|
26
|
+
if (err instanceof ApiError &&
|
|
27
|
+
!!err.statusCode &&
|
|
28
|
+
err.statusCode >= 500) {
|
|
27
29
|
onRetry?.(err);
|
|
28
30
|
// avoid re-adding user message to conversation history on retry
|
|
29
31
|
text = "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSendMessageWithRetries.mjs","sources":["../../../../src/hooks/useSendMessageWithRetries.ts"],"sourcesContent":["import { ApiError, useChatActions } from \"@yext/chat-headless-react\";\nimport { useCallback } from \"react\";\n\n/**\n * Returns a function that sends a message to the chat API with retries\n * if the API returns a 5xx status code.\n
|
|
1
|
+
{"version":3,"file":"useSendMessageWithRetries.mjs","sources":["../../../../src/hooks/useSendMessageWithRetries.ts"],"sourcesContent":["import { ApiError, useChatActions } from \"@yext/chat-headless-react\";\nimport { useCallback } from \"react\";\n\n/**\n * Returns a function that sends a message to the chat API with retries\n * if the API returns a 5xx status code.\n *\n * @remarks\n * The function will throw the error if the maximum number of retries is reached\n * or if the error is not a 5xx status code.\n *\n * @internal\n *\n * @param stream - If true, use streaming API\n * @param maxRetries - Maximum number of retries\n * @param onRetry - Callback to handle error on each retry\n *\n */\nexport function useSendMessageWithRetries(\n stream = false,\n maxRetries = 0,\n onRetry?: (e: unknown) => void\n): (input: string) => Promise<void> {\n const chat = useChatActions();\n return useCallback(\n async (input: string) => {\n let err: unknown;\n let text = input;\n for (let numRetries = 0; numRetries <= maxRetries; numRetries++) {\n if (numRetries > 0 && !!err) {\n if (\n err instanceof ApiError &&\n !!err.statusCode &&\n err.statusCode >= 500\n ) {\n onRetry?.(err);\n // avoid re-adding user message to conversation history on retry\n text = \"\";\n } else {\n throw err;\n }\n }\n try {\n await (stream\n ? chat.streamNextMessage(text)\n : chat.getNextMessage(text));\n return;\n } catch (e) {\n err = e;\n }\n }\n throw err;\n },\n [chat, maxRetries, onRetry, stream]\n );\n}\n"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;;AAcG;AACG,SAAU,yBAAyB,CACvC,MAAM,GAAG,KAAK,EACd,UAAU,GAAG,CAAC,EACd,OAA8B,EAAA;AAE9B,IAAA,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;AAC9B,IAAA,OAAO,WAAW,CAChB,OAAO,KAAa,KAAI;AACtB,QAAA,IAAI,GAAY,CAAC;QACjB,IAAI,IAAI,GAAG,KAAK,CAAC;QACjB,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,IAAI,UAAU,EAAE,UAAU,EAAE,EAAE;AAC/D,YAAA,IAAI,UAAU,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE;gBAC3B,IACE,GAAG,YAAY,QAAQ;oBACvB,CAAC,CAAC,GAAG,CAAC,UAAU;AAChB,oBAAA,GAAG,CAAC,UAAU,IAAI,GAAG,EACrB;AACA,oBAAA,OAAO,GAAG,GAAG,CAAC,CAAC;;oBAEf,IAAI,GAAG,EAAE,CAAC;AACX,iBAAA;AAAM,qBAAA;AACL,oBAAA,MAAM,GAAG,CAAC;AACX,iBAAA;AACF,aAAA;YACD,IAAI;AACF,gBAAA,OAAO,MAAM;AACX,sBAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;sBAC5B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/B,OAAO;AACR,aAAA;AAAC,YAAA,OAAO,CAAC,EAAE;gBACV,GAAG,GAAG,CAAC,CAAC;AACT,aAAA;AACF,SAAA;AACD,QAAA,MAAM,GAAG,CAAC;KACX,EACD,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CACpC,CAAC;AACJ;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yext/chat-ui-react",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "A library of React Components for powering Yext Chat integrations.",
|
|
5
5
|
"author": "clippy@yext.com",
|
|
6
6
|
"main": "./lib/commonjs/src/index.js",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"typescript": "^5.0.4"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
|
-
"@yext/chat-headless-react": "^0.
|
|
94
|
+
"@yext/chat-headless-react": "^0.8.0",
|
|
95
95
|
"react": "^16.14 || ^17 || ^18",
|
|
96
96
|
"react-dom": "^16.14 || ^17 || || ^18"
|
|
97
97
|
},
|
|
@@ -63,7 +63,7 @@ export interface ChatInputProps {
|
|
|
63
63
|
* A function which is called when a retryable error occurs from
|
|
64
64
|
* Chat API while processing the user's message.
|
|
65
65
|
*/
|
|
66
|
-
onRetry?: (e: unknown) => void
|
|
66
|
+
onRetry?: (e: unknown) => void;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
/**
|
|
@@ -92,7 +92,7 @@ export function ChatInput({
|
|
|
92
92
|
(state) => state.conversation.canSendMessage
|
|
93
93
|
);
|
|
94
94
|
const defaultHandleApiError = useDefaultHandleApiError();
|
|
95
|
-
const sendMessageWithRetries =
|
|
95
|
+
const sendMessageWithRetries = useSendMessageWithRetries(stream, 1, onRetry);
|
|
96
96
|
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
97
97
|
|
|
98
98
|
const sendMessage = useCallback(async () => {
|
|
@@ -100,18 +100,27 @@ export function ChatInput({
|
|
|
100
100
|
sendMessageWithRetries(input)
|
|
101
101
|
.catch(handleError ?? defaultHandleApiError)
|
|
102
102
|
.finally(() => {
|
|
103
|
-
onSend?.(input)
|
|
104
|
-
})
|
|
105
|
-
}, [
|
|
103
|
+
onSend?.(input);
|
|
104
|
+
});
|
|
105
|
+
}, [
|
|
106
|
+
sendMessageWithRetries,
|
|
107
|
+
input,
|
|
108
|
+
handleError,
|
|
109
|
+
defaultHandleApiError,
|
|
110
|
+
onSend,
|
|
111
|
+
]);
|
|
106
112
|
|
|
107
113
|
const handleKeyDown = useCallback(
|
|
108
114
|
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
|
109
|
-
if (
|
|
115
|
+
if (
|
|
116
|
+
!e.shiftKey &&
|
|
117
|
+
e.key === "Enter" &&
|
|
110
118
|
// The Japanese Keyboard uses "Enter" key to convert from Hiragana to Kanji.
|
|
111
119
|
// "isComposing" is a flag that indicates whether the event is part of an ongoing composition session.
|
|
112
120
|
// Safari does not support `isComposing` with the Japanese IME event,
|
|
113
121
|
// so we have to additionally check for the keyCode to handle that edge case.
|
|
114
|
-
!(e.nativeEvent.isComposing || e.keyCode === 229)
|
|
122
|
+
!(e.nativeEvent.isComposing || e.keyCode === 229)
|
|
123
|
+
) {
|
|
115
124
|
e.preventDefault();
|
|
116
125
|
if (canSendMessage && input.trim().length !== 0) {
|
|
117
126
|
sendMessage();
|
|
@@ -75,6 +75,10 @@ export interface ChatPanelProps
|
|
|
75
75
|
* can click on instead of typing their own.
|
|
76
76
|
*/
|
|
77
77
|
messageSuggestions?: string[];
|
|
78
|
+
/** Link target open behavior on click.
|
|
79
|
+
* Defaults to "_blank".
|
|
80
|
+
*/
|
|
81
|
+
linkTarget?: string;
|
|
78
82
|
/** A callback which is called when user clicks a link. */
|
|
79
83
|
onLinkClick?: (href?: string) => void;
|
|
80
84
|
/**
|
|
@@ -101,9 +105,10 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
101
105
|
stream,
|
|
102
106
|
handleError,
|
|
103
107
|
messageSuggestions,
|
|
108
|
+
linkTarget = "_blank",
|
|
104
109
|
onLinkClick,
|
|
105
|
-
onSend:onSendProp,
|
|
106
|
-
onRetry:onRetryProp,
|
|
110
|
+
onSend: onSendProp,
|
|
111
|
+
onRetry: onRetryProp,
|
|
107
112
|
retryText = "Error occurred. Retrying",
|
|
108
113
|
} = props;
|
|
109
114
|
const messages = useChatState((state) => state.conversation.messages);
|
|
@@ -116,15 +121,21 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
116
121
|
useFetchInitialMessage(handleError, stream);
|
|
117
122
|
|
|
118
123
|
const [retry, setRetry] = useState(false);
|
|
119
|
-
const onSend = useCallback(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
const onSend = useCallback(
|
|
125
|
+
(message: string) => {
|
|
126
|
+
onSendProp?.(message);
|
|
127
|
+
setRetry(false);
|
|
128
|
+
},
|
|
129
|
+
[onSendProp]
|
|
130
|
+
);
|
|
123
131
|
|
|
124
|
-
const onRetry = useCallback(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
const onRetry = useCallback(
|
|
133
|
+
(e: unknown) => {
|
|
134
|
+
onRetryProp?.(e);
|
|
135
|
+
setRetry(true);
|
|
136
|
+
},
|
|
137
|
+
[onRetryProp]
|
|
138
|
+
);
|
|
128
139
|
|
|
129
140
|
useEffect(() => {
|
|
130
141
|
reportAnalyticsEvent({
|
|
@@ -190,14 +201,21 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
190
201
|
{...props}
|
|
191
202
|
customCssClasses={cssClasses.messageBubbleCssClasses}
|
|
192
203
|
message={message}
|
|
204
|
+
linkTarget={linkTarget}
|
|
193
205
|
onLinkClick={onLinkClick}
|
|
194
206
|
/>
|
|
195
207
|
</div>
|
|
196
208
|
))}
|
|
197
|
-
{loading &&
|
|
198
|
-
<
|
|
199
|
-
|
|
200
|
-
|
|
209
|
+
{loading && (
|
|
210
|
+
<div className="flex">
|
|
211
|
+
<LoadingDots />
|
|
212
|
+
{retry && (
|
|
213
|
+
<p className="text-slate-500 text-[13px] font-bold">
|
|
214
|
+
{retryText}
|
|
215
|
+
</p>
|
|
216
|
+
)}
|
|
217
|
+
</div>
|
|
218
|
+
)}
|
|
201
219
|
</div>
|
|
202
220
|
</div>
|
|
203
221
|
<div className={cssClasses.inputContainer}>
|
|
@@ -222,6 +240,7 @@ export function ChatPanel(props: ChatPanelProps) {
|
|
|
222
240
|
<Markdown
|
|
223
241
|
content={footer}
|
|
224
242
|
linkClickEvent="WEBSITE"
|
|
243
|
+
linkTarget={linkTarget}
|
|
225
244
|
onLinkClick={onLinkClick}
|
|
226
245
|
customCssClasses={footerCssClasses}
|
|
227
246
|
/>
|
|
@@ -162,12 +162,13 @@ export function ChatPopUp(props: ChatPopUpProps) {
|
|
|
162
162
|
// to avoid message requests immediately on load while the popup is still "hidden"
|
|
163
163
|
const [renderChat, setRenderChat] = useState(false);
|
|
164
164
|
|
|
165
|
-
|
|
166
165
|
// only fetch initial message when ChatPanel is closed on load (otherwise, it will be fetched in ChatPanel)
|
|
167
166
|
useFetchInitialMessage(
|
|
168
167
|
showInitialMessagePopUp ? console.error : handleError,
|
|
169
168
|
false,
|
|
170
|
-
(showUnreadNotification || showInitialMessagePopUp) &&
|
|
169
|
+
(showUnreadNotification || showInitialMessagePopUp) &&
|
|
170
|
+
!renderChat &&
|
|
171
|
+
!openOnLoad
|
|
171
172
|
);
|
|
172
173
|
|
|
173
174
|
useEffect(() => {
|
|
@@ -180,7 +181,7 @@ export function ChatPopUp(props: ChatPopUpProps) {
|
|
|
180
181
|
}, [messages.length, openOnLoad, renderChat]);
|
|
181
182
|
|
|
182
183
|
const onClick = useCallback(() => {
|
|
183
|
-
setShowChat(prev => !prev);
|
|
184
|
+
setShowChat((prev) => !prev);
|
|
184
185
|
setRenderChat(true);
|
|
185
186
|
setshowInitialMessage(false);
|
|
186
187
|
}, []);
|
|
@@ -46,6 +46,8 @@ interface MarkdownProps {
|
|
|
46
46
|
* Defaults to 'CHAT_LINK_CLICK'.
|
|
47
47
|
*/
|
|
48
48
|
linkClickEvent?: "WEBSITE" | "CHAT_LINK_CLICK";
|
|
49
|
+
/** Link target open behavior on click. */
|
|
50
|
+
linkTarget?: string;
|
|
49
51
|
/** A callback which is called when a link is clicked. */
|
|
50
52
|
onLinkClick?: (href?: string) => void;
|
|
51
53
|
}
|
|
@@ -64,6 +66,7 @@ export function Markdown({
|
|
|
64
66
|
responseId,
|
|
65
67
|
customCssClasses,
|
|
66
68
|
linkClickEvent = "CHAT_LINK_CLICK",
|
|
69
|
+
linkTarget,
|
|
67
70
|
onLinkClick,
|
|
68
71
|
}: MarkdownProps) {
|
|
69
72
|
const reportAnalyticsEvent = useReportAnalyticsEvent();
|
|
@@ -86,7 +89,7 @@ export function Markdown({
|
|
|
86
89
|
<a
|
|
87
90
|
{...props}
|
|
88
91
|
onClick={createClickHandlerFn(props.href)}
|
|
89
|
-
target=
|
|
92
|
+
target={linkTarget}
|
|
90
93
|
rel="noopener noreferrer"
|
|
91
94
|
className={cssClasses.link}
|
|
92
95
|
>
|
|
@@ -100,6 +103,7 @@ export function Markdown({
|
|
|
100
103
|
linkClickEvent,
|
|
101
104
|
responseId,
|
|
102
105
|
cssClasses,
|
|
106
|
+
linkTarget,
|
|
103
107
|
onLinkClick,
|
|
104
108
|
]);
|
|
105
109
|
|
|
@@ -75,6 +75,8 @@ export interface MessageBubbleProps {
|
|
|
75
75
|
formatTimestamp?: (timestamp: string) => string;
|
|
76
76
|
/** CSS classes for customizing the component styling. */
|
|
77
77
|
customCssClasses?: MessageBubbleCssClasses;
|
|
78
|
+
/** Link target open behavior on click. */
|
|
79
|
+
linkTarget?: string;
|
|
78
80
|
/** A callback which is called when user clicks a link. */
|
|
79
81
|
onLinkClick?: (href?: string) => void;
|
|
80
82
|
}
|
|
@@ -92,6 +94,7 @@ export function MessageBubble({
|
|
|
92
94
|
showTimestamp = true,
|
|
93
95
|
customCssClasses,
|
|
94
96
|
formatTimestamp = defaultFormatTimestamp,
|
|
97
|
+
linkTarget,
|
|
95
98
|
onLinkClick,
|
|
96
99
|
}: MessageBubbleProps) {
|
|
97
100
|
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);
|
|
@@ -141,6 +144,7 @@ export function MessageBubble({
|
|
|
141
144
|
content={message.text}
|
|
142
145
|
responseId={message.responseId}
|
|
143
146
|
customCssClasses={markdownCssClasses}
|
|
147
|
+
linkTarget={linkTarget}
|
|
144
148
|
onLinkClick={onLinkClick}
|
|
145
149
|
/>
|
|
146
150
|
</div>
|
|
@@ -36,7 +36,7 @@ export interface MessageSuggestionsProps {
|
|
|
36
36
|
/** {@inheritdoc ChatInputProps.onSend} */
|
|
37
37
|
onSend?: (message: string) => void;
|
|
38
38
|
/** {@inheritdoc ChatInputProps.onRetry} */
|
|
39
|
-
onRetry?: (e: unknown) => void
|
|
39
|
+
onRetry?: (e: unknown) => void;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const defaultClassnames: MessageSuggestionCssClasses = withStylelessCssClasses(
|
|
@@ -65,7 +65,7 @@ export const MessageSuggestions: React.FC<MessageSuggestionsProps> = ({
|
|
|
65
65
|
const actions = useChatActions();
|
|
66
66
|
const notes = useChatState((state) => state.conversation.notes);
|
|
67
67
|
const defaultHandleApiError = useDefaultHandleApiError();
|
|
68
|
-
const sendMessageWithRetries =
|
|
68
|
+
const sendMessageWithRetries = useSendMessageWithRetries(stream, 1, onRetry);
|
|
69
69
|
const sendMsg = useCallback(
|
|
70
70
|
(msg: string) => {
|
|
71
71
|
const newNotes = {
|
|
@@ -76,10 +76,17 @@ export const MessageSuggestions: React.FC<MessageSuggestionsProps> = ({
|
|
|
76
76
|
sendMessageWithRetries(msg)
|
|
77
77
|
.catch(handleError ?? defaultHandleApiError)
|
|
78
78
|
.finally(() => {
|
|
79
|
-
onSend?.(msg)
|
|
80
|
-
})
|
|
79
|
+
onSend?.(msg);
|
|
80
|
+
});
|
|
81
81
|
},
|
|
82
|
-
[
|
|
82
|
+
[
|
|
83
|
+
notes,
|
|
84
|
+
actions,
|
|
85
|
+
sendMessageWithRetries,
|
|
86
|
+
handleError,
|
|
87
|
+
defaultHandleApiError,
|
|
88
|
+
onSend,
|
|
89
|
+
]
|
|
83
90
|
);
|
|
84
91
|
|
|
85
92
|
const classes = useComposedCssClasses(defaultClassnames, customCssClasses);
|
|
@@ -16,7 +16,7 @@ import { useDefaultHandleApiError } from "../hooks/useDefaultHandleApiError";
|
|
|
16
16
|
export function useFetchInitialMessage(
|
|
17
17
|
handleError?: (e: unknown) => void,
|
|
18
18
|
stream = false,
|
|
19
|
-
customCondition = true
|
|
19
|
+
customCondition = true
|
|
20
20
|
) {
|
|
21
21
|
const chat = useChatActions();
|
|
22
22
|
const defaultHandleApiError = useDefaultHandleApiError();
|
|
@@ -24,12 +24,20 @@ export function useFetchInitialMessage(
|
|
|
24
24
|
const canSendMessage = useChatState(
|
|
25
25
|
(state) => state.conversation.canSendMessage
|
|
26
26
|
);
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
useEffect(() => {
|
|
29
29
|
if (messages.length !== 0 || !canSendMessage || !customCondition) {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
const res = stream ? chat.streamNextMessage() : chat.getNextMessage();
|
|
33
33
|
res.catch((e) => (handleError ? handleError(e) : defaultHandleApiError(e)));
|
|
34
|
-
}, [
|
|
34
|
+
}, [
|
|
35
|
+
chat,
|
|
36
|
+
stream,
|
|
37
|
+
handleError,
|
|
38
|
+
defaultHandleApiError,
|
|
39
|
+
canSendMessage,
|
|
40
|
+
customCondition,
|
|
41
|
+
messages.length,
|
|
42
|
+
]);
|
|
35
43
|
}
|
|
@@ -4,46 +4,53 @@ import { useCallback } from "react";
|
|
|
4
4
|
/**
|
|
5
5
|
* Returns a function that sends a message to the chat API with retries
|
|
6
6
|
* if the API returns a 5xx status code.
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
8
|
* @remarks
|
|
9
9
|
* The function will throw the error if the maximum number of retries is reached
|
|
10
10
|
* or if the error is not a 5xx status code.
|
|
11
|
-
*
|
|
11
|
+
*
|
|
12
12
|
* @internal
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* @param stream - If true, use streaming API
|
|
15
15
|
* @param maxRetries - Maximum number of retries
|
|
16
16
|
* @param onRetry - Callback to handle error on each retry
|
|
17
|
-
*
|
|
17
|
+
*
|
|
18
18
|
*/
|
|
19
19
|
export function useSendMessageWithRetries(
|
|
20
20
|
stream = false,
|
|
21
21
|
maxRetries = 0,
|
|
22
22
|
onRetry?: (e: unknown) => void
|
|
23
23
|
): (input: string) => Promise<void> {
|
|
24
|
-
const chat = useChatActions()
|
|
25
|
-
return useCallback(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
const chat = useChatActions();
|
|
25
|
+
return useCallback(
|
|
26
|
+
async (input: string) => {
|
|
27
|
+
let err: unknown;
|
|
28
|
+
let text = input;
|
|
29
|
+
for (let numRetries = 0; numRetries <= maxRetries; numRetries++) {
|
|
30
|
+
if (numRetries > 0 && !!err) {
|
|
31
|
+
if (
|
|
32
|
+
err instanceof ApiError &&
|
|
33
|
+
!!err.statusCode &&
|
|
34
|
+
err.statusCode >= 500
|
|
35
|
+
) {
|
|
36
|
+
onRetry?.(err);
|
|
37
|
+
// avoid re-adding user message to conversation history on retry
|
|
38
|
+
text = "";
|
|
39
|
+
} else {
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
await (stream
|
|
45
|
+
? chat.streamNextMessage(text)
|
|
46
|
+
: chat.getNextMessage(text));
|
|
47
|
+
return;
|
|
48
|
+
} catch (e) {
|
|
49
|
+
err = e;
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return;
|
|
43
|
-
} catch (e) {
|
|
44
|
-
err = e;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
throw err
|
|
48
|
-
}, [chat, maxRetries, onRetry, stream])
|
|
52
|
+
throw err;
|
|
53
|
+
},
|
|
54
|
+
[chat, maxRetries, onRetry, stream]
|
|
55
|
+
);
|
|
49
56
|
}
|