@servicetitan/titan-chatbot-ui-anvil2 3.1.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.
Files changed (219) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/README.md +15 -0
  3. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.d.ts +2 -0
  4. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.d.ts.map +1 -0
  5. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.js +8 -0
  6. package/dist/components/chatbot/__tests-cy__/chatbot-help-center.test.js.map +1 -0
  7. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.d.ts +2 -0
  8. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.d.ts.map +1 -0
  9. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.js +8 -0
  10. package/dist/components/chatbot/__tests-cy__/chatbot-live.test.js.map +1 -0
  11. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.d.ts +2 -0
  12. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.d.ts.map +1 -0
  13. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.js +8 -0
  14. package/dist/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.js.map +1 -0
  15. package/dist/components/chatbot/__tests-cy__/chatbot.test.d.ts +2 -0
  16. package/dist/components/chatbot/__tests-cy__/chatbot.test.d.ts.map +1 -0
  17. package/dist/components/chatbot/__tests-cy__/chatbot.test.js +8 -0
  18. package/dist/components/chatbot/__tests-cy__/chatbot.test.js.map +1 -0
  19. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.d.ts +6 -0
  20. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.d.ts.map +1 -0
  21. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.js +21 -0
  22. package/dist/components/chatbot/chatbot-to-chat-provider-adapter.js.map +1 -0
  23. package/dist/components/chatbot/chatbot.d.ts +10 -0
  24. package/dist/components/chatbot/chatbot.d.ts.map +1 -0
  25. package/dist/components/chatbot/chatbot.js +69 -0
  26. package/dist/components/chatbot/chatbot.js.map +1 -0
  27. package/dist/components/chatbot/chatbot.module.less +4 -0
  28. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-dialog.test.d.ts +2 -0
  29. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-dialog.test.d.ts.map +1 -0
  30. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-dialog.test.js +8 -0
  31. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-dialog.test.js.map +1 -0
  32. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-link.test.d.ts +2 -0
  33. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-link.test.d.ts.map +1 -0
  34. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-link.test.js +8 -0
  35. package/dist/components/chatbot/dialog/__tests-cy__/chatbot-restart-link.test.js.map +1 -0
  36. package/dist/components/chatbot/dialog/chatbot-restart-dialog.d.ts +6 -0
  37. package/dist/components/chatbot/dialog/chatbot-restart-dialog.d.ts.map +1 -0
  38. package/dist/components/chatbot/dialog/chatbot-restart-dialog.js +20 -0
  39. package/dist/components/chatbot/dialog/chatbot-restart-dialog.js.map +1 -0
  40. package/dist/components/chatbot/dialog/chatbot-restart-link.d.ts +4 -0
  41. package/dist/components/chatbot/dialog/chatbot-restart-link.d.ts.map +1 -0
  42. package/dist/components/chatbot/dialog/chatbot-restart-link.js +13 -0
  43. package/dist/components/chatbot/dialog/chatbot-restart-link.js.map +1 -0
  44. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.d.ts +2 -0
  45. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.d.ts.map +1 -0
  46. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.js +8 -0
  47. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.js.map +1 -0
  48. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.d.ts +2 -0
  49. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.d.ts.map +1 -0
  50. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.js +8 -0
  51. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.js.map +1 -0
  52. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-popover.test.d.ts +2 -0
  53. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-popover.test.d.ts.map +1 -0
  54. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-popover.test.js +8 -0
  55. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-popover.test.js.map +1 -0
  56. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-session-feedback-modal.test.d.ts +2 -0
  57. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-session-feedback-modal.test.d.ts.map +1 -0
  58. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-session-feedback-modal.test.js +8 -0
  59. package/dist/components/chatbot/feedback/__tests-cy__/chatbot-session-feedback-modal.test.js.map +1 -0
  60. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.d.ts +3 -0
  61. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.d.ts.map +1 -0
  62. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.js +16 -0
  63. package/dist/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.js.map +1 -0
  64. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.d.ts +3 -0
  65. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.d.ts.map +1 -0
  66. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.js +18 -0
  67. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.js.map +1 -0
  68. package/dist/components/chatbot/feedback/chatbot-message-feedback-form.module.less +15 -0
  69. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.d.ts +9 -0
  70. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.d.ts.map +1 -0
  71. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.js +61 -0
  72. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.js.map +1 -0
  73. package/dist/components/chatbot/feedback/chatbot-message-feedback-popover.module.less +14 -0
  74. package/dist/components/chatbot/feedback/chatbot-message-feedback.d.ts +9 -0
  75. package/dist/components/chatbot/feedback/chatbot-message-feedback.d.ts.map +1 -0
  76. package/dist/components/chatbot/feedback/chatbot-message-feedback.js +17 -0
  77. package/dist/components/chatbot/feedback/chatbot-message-feedback.js.map +1 -0
  78. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.d.ts +4 -0
  79. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.d.ts.map +1 -0
  80. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.js +15 -0
  81. package/dist/components/chatbot/feedback/chatbot-session-feedback-link.js.map +1 -0
  82. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.d.ts +5 -0
  83. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.d.ts.map +1 -0
  84. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.js +25 -0
  85. package/dist/components/chatbot/feedback/chatbot-session-feedback-modal.js.map +1 -0
  86. package/dist/components/chatbot/filters/__tests-cy__/chatbot-filters.test.d.ts +2 -0
  87. package/dist/components/chatbot/filters/__tests-cy__/chatbot-filters.test.d.ts.map +1 -0
  88. package/dist/components/chatbot/filters/__tests-cy__/chatbot-filters.test.js +8 -0
  89. package/dist/components/chatbot/filters/__tests-cy__/chatbot-filters.test.js.map +1 -0
  90. package/dist/components/chatbot/filters/chatbot-filter-button.d.ts +7 -0
  91. package/dist/components/chatbot/filters/chatbot-filter-button.d.ts.map +1 -0
  92. package/dist/components/chatbot/filters/chatbot-filter-button.js +39 -0
  93. package/dist/components/chatbot/filters/chatbot-filter-button.js.map +1 -0
  94. package/dist/components/chatbot/filters/chatbot-filter.d.ts +8 -0
  95. package/dist/components/chatbot/filters/chatbot-filter.d.ts.map +1 -0
  96. package/dist/components/chatbot/filters/chatbot-filter.js +71 -0
  97. package/dist/components/chatbot/filters/chatbot-filter.js.map +1 -0
  98. package/dist/components/chatbot/filters/chatbot-filter.module.css +43 -0
  99. package/dist/components/chatbot/filters/chatbot-filters.d.ts +5 -0
  100. package/dist/components/chatbot/filters/chatbot-filters.d.ts.map +1 -0
  101. package/dist/components/chatbot/filters/chatbot-filters.js +11 -0
  102. package/dist/components/chatbot/filters/chatbot-filters.js.map +1 -0
  103. package/dist/components/chatbot/messages/__tests-cy__/chatbot-links.test.d.ts +2 -0
  104. package/dist/components/chatbot/messages/__tests-cy__/chatbot-links.test.d.ts.map +1 -0
  105. package/dist/components/chatbot/messages/__tests-cy__/chatbot-links.test.js +8 -0
  106. package/dist/components/chatbot/messages/__tests-cy__/chatbot-links.test.js.map +1 -0
  107. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer-readonly.test.d.ts +2 -0
  108. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer-readonly.test.d.ts.map +1 -0
  109. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer-readonly.test.js +8 -0
  110. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer-readonly.test.js.map +1 -0
  111. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.d.ts +2 -0
  112. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.d.ts.map +1 -0
  113. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.js +8 -0
  114. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.js.map +1 -0
  115. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.d.ts +2 -0
  116. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.d.ts.map +1 -0
  117. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.js +8 -0
  118. package/dist/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.js.map +1 -0
  119. package/dist/components/chatbot/messages/chatbot-links.d.ts +15 -0
  120. package/dist/components/chatbot/messages/chatbot-links.d.ts.map +1 -0
  121. package/dist/components/chatbot/messages/chatbot-links.js +21 -0
  122. package/dist/components/chatbot/messages/chatbot-links.js.map +1 -0
  123. package/dist/components/chatbot/messages/chatbot-links.module.less +24 -0
  124. package/dist/components/chatbot/messages/chatbot-message-agent-footer.d.ts +8 -0
  125. package/dist/components/chatbot/messages/chatbot-message-agent-footer.d.ts.map +1 -0
  126. package/dist/components/chatbot/messages/chatbot-message-agent-footer.js +13 -0
  127. package/dist/components/chatbot/messages/chatbot-message-agent-footer.js.map +1 -0
  128. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.d.ts +6 -0
  129. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.d.ts.map +1 -0
  130. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.js +17 -0
  131. package/dist/components/chatbot/messages/chatbot-message-answer-readonly.js.map +1 -0
  132. package/dist/components/chatbot/messages/chatbot-message-answer.d.ts +6 -0
  133. package/dist/components/chatbot/messages/chatbot-message-answer.d.ts.map +1 -0
  134. package/dist/components/chatbot/messages/chatbot-message-answer.js +29 -0
  135. package/dist/components/chatbot/messages/chatbot-message-answer.js.map +1 -0
  136. package/dist/components/chatbot/messages/chatbot-message-answer.module.less +3 -0
  137. package/dist/components/chatbot/messages/chatbot-message-timeout.d.ts +6 -0
  138. package/dist/components/chatbot/messages/chatbot-message-timeout.d.ts.map +1 -0
  139. package/dist/components/chatbot/messages/chatbot-message-timeout.js +17 -0
  140. package/dist/components/chatbot/messages/chatbot-message-timeout.js.map +1 -0
  141. package/dist/components/chatbot/messages/chatbot-message-typing.d.ts +8 -0
  142. package/dist/components/chatbot/messages/chatbot-message-typing.d.ts.map +1 -0
  143. package/dist/components/chatbot/messages/chatbot-message-typing.js +27 -0
  144. package/dist/components/chatbot/messages/chatbot-message-typing.js.map +1 -0
  145. package/dist/components/chatbot/messages/chatbot-message-welcome.d.ts +3 -0
  146. package/dist/components/chatbot/messages/chatbot-message-welcome.d.ts.map +1 -0
  147. package/dist/components/chatbot/messages/chatbot-message-welcome.js +4 -0
  148. package/dist/components/chatbot/messages/chatbot-message-welcome.js.map +1 -0
  149. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.d.ts +6 -0
  150. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.d.ts.map +1 -0
  151. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.js +12 -0
  152. package/dist/components/chatbot/templates/chatbot-message-template-agent-readonly.js.map +1 -0
  153. package/dist/components/chatbot/templates/chatbot-message-template-agent.d.ts +6 -0
  154. package/dist/components/chatbot/templates/chatbot-message-template-agent.d.ts.map +1 -0
  155. package/dist/components/chatbot/templates/chatbot-message-template-agent.js +10 -0
  156. package/dist/components/chatbot/templates/chatbot-message-template-agent.js.map +1 -0
  157. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.d.ts +6 -0
  158. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.d.ts.map +1 -0
  159. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.js +7 -0
  160. package/dist/components/chatbot/templates/chatbot-message-template-user-readonly.js.map +1 -0
  161. package/dist/index.d.ts +6 -0
  162. package/dist/index.d.ts.map +1 -0
  163. package/dist/index.js +6 -0
  164. package/dist/index.js.map +1 -0
  165. package/package.json +59 -0
  166. package/src/components/chatbot/__tests-cy__/chatbot-help-center.test.tsx +9 -0
  167. package/src/components/chatbot/__tests-cy__/chatbot-live.test.tsx +7 -0
  168. package/src/components/chatbot/__tests-cy__/chatbot-titan-chatbot.test.tsx +9 -0
  169. package/src/components/chatbot/__tests-cy__/chatbot.test.tsx +7 -0
  170. package/src/components/chatbot/chatbot-to-chat-provider-adapter.tsx +36 -0
  171. package/src/components/chatbot/chatbot.module.less +4 -0
  172. package/src/components/chatbot/chatbot.module.less.d.ts +3 -0
  173. package/src/components/chatbot/chatbot.tsx +99 -0
  174. package/src/components/chatbot/dialog/__tests-cy__/chatbot-restart-dialog.test.tsx +9 -0
  175. package/src/components/chatbot/dialog/__tests-cy__/chatbot-restart-link.test.tsx +9 -0
  176. package/src/components/chatbot/dialog/chatbot-restart-dialog.tsx +41 -0
  177. package/src/components/chatbot/dialog/chatbot-restart-link.tsx +29 -0
  178. package/src/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form-guardrail.test.tsx +10 -0
  179. package/src/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-form.test.tsx +9 -0
  180. package/src/components/chatbot/feedback/__tests-cy__/chatbot-message-feedback-popover.test.tsx +9 -0
  181. package/src/components/chatbot/feedback/__tests-cy__/chatbot-session-feedback-modal.test.tsx +9 -0
  182. package/src/components/chatbot/feedback/chatbot-message-feedback-form-guardrail.tsx +40 -0
  183. package/src/components/chatbot/feedback/chatbot-message-feedback-form.module.less +15 -0
  184. package/src/components/chatbot/feedback/chatbot-message-feedback-form.module.less.d.ts +4 -0
  185. package/src/components/chatbot/feedback/chatbot-message-feedback-form.tsx +76 -0
  186. package/src/components/chatbot/feedback/chatbot-message-feedback-popover.module.less +14 -0
  187. package/src/components/chatbot/feedback/chatbot-message-feedback-popover.module.less.d.ts +5 -0
  188. package/src/components/chatbot/feedback/chatbot-message-feedback-popover.tsx +207 -0
  189. package/src/components/chatbot/feedback/chatbot-message-feedback.tsx +27 -0
  190. package/src/components/chatbot/feedback/chatbot-session-feedback-link.tsx +27 -0
  191. package/src/components/chatbot/feedback/chatbot-session-feedback-modal.tsx +95 -0
  192. package/src/components/chatbot/filters/__tests-cy__/chatbot-filters.test.tsx +9 -0
  193. package/src/components/chatbot/filters/chatbot-filter-button.tsx +58 -0
  194. package/src/components/chatbot/filters/chatbot-filter.module.css +43 -0
  195. package/src/components/chatbot/filters/chatbot-filter.module.css.d.ts +5 -0
  196. package/src/components/chatbot/filters/chatbot-filter.tsx +166 -0
  197. package/src/components/chatbot/filters/chatbot-filters.tsx +17 -0
  198. package/src/components/chatbot/messages/__tests-cy__/chatbot-links.test.tsx +9 -0
  199. package/src/components/chatbot/messages/__tests-cy__/chatbot-message-answer-readonly.test.tsx +9 -0
  200. package/src/components/chatbot/messages/__tests-cy__/chatbot-message-answer.test.tsx +9 -0
  201. package/src/components/chatbot/messages/__tests-cy__/chatbot-message-typing.test.tsx +9 -0
  202. package/src/components/chatbot/messages/chatbot-links.module.less +24 -0
  203. package/src/components/chatbot/messages/chatbot-links.module.less.d.ts +5 -0
  204. package/src/components/chatbot/messages/chatbot-links.tsx +73 -0
  205. package/src/components/chatbot/messages/chatbot-message-agent-footer.tsx +35 -0
  206. package/src/components/chatbot/messages/chatbot-message-answer-readonly.tsx +39 -0
  207. package/src/components/chatbot/messages/chatbot-message-answer.module.less +3 -0
  208. package/src/components/chatbot/messages/chatbot-message-answer.module.less.d.ts +3 -0
  209. package/src/components/chatbot/messages/chatbot-message-answer.tsx +55 -0
  210. package/src/components/chatbot/messages/chatbot-message-timeout.tsx +20 -0
  211. package/src/components/chatbot/messages/chatbot-message-typing.tsx +43 -0
  212. package/src/components/chatbot/messages/chatbot-message-welcome.tsx +16 -0
  213. package/src/components/chatbot/templates/chatbot-message-template-agent-readonly.tsx +25 -0
  214. package/src/components/chatbot/templates/chatbot-message-template-agent.tsx +25 -0
  215. package/src/components/chatbot/templates/chatbot-message-template-user-readonly.tsx +16 -0
  216. package/src/cypress.d.ts +10 -0
  217. package/src/index.ts +5 -0
  218. package/tsconfig.json +25 -0
  219. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,27 @@
1
+ import { useDependencies } from '@servicetitan/react-ioc';
2
+ import { CHATBOT_UI_STORE_TOKEN, Models } from '@servicetitan/titan-chatbot-api';
3
+ import { observer } from 'mobx-react';
4
+ import { FC } from 'react';
5
+ import { ChatbotMessageFeedbackPopover } from './chatbot-message-feedback-popover';
6
+
7
+ interface IChatbotFeedbackProps {
8
+ botMessage: Models.IBotMessage;
9
+ className?: string;
10
+ }
11
+
12
+ export const ChatbotMessageFeedback: FC<IChatbotFeedbackProps> = observer(
13
+ ({ botMessage, className }) => {
14
+ const [chatbotUiStore] = useDependencies(CHATBOT_UI_STORE_TOKEN);
15
+
16
+ // We show feedback for all messages with normal answer and for guardrailed messages if internal chatbot setting is enabled
17
+ const showGuardrailFeedback = Boolean(
18
+ chatbotUiStore.customizations?.feedback?.showGuardrailFeedback
19
+ );
20
+ const isFeedbackVisible = showGuardrailFeedback || !botMessage.isGuardrailed;
21
+
22
+ if (!isFeedbackVisible) {
23
+ return null;
24
+ }
25
+ return <ChatbotMessageFeedbackPopover className={className} botMessage={botMessage} />;
26
+ }
27
+ );
@@ -0,0 +1,27 @@
1
+ import { Link, LinkProps } from '@servicetitan/anvil2';
2
+ import { FC, Fragment, useCallback, useState } from 'react';
3
+ import { ChatbotSessionFeedbackModal } from './chatbot-session-feedback-modal';
4
+
5
+ export const ChatbotSessionFeedbackLink: FC<LinkProps> = ({ children, onClick, ...rest }) => {
6
+ const [isFeedbackOpen, setIsFeedbackOpen] = useState(false);
7
+
8
+ const handleFeedback = useCallback(() => {
9
+ setIsFeedbackOpen(false);
10
+ }, []);
11
+
12
+ return (
13
+ <Fragment>
14
+ <Link
15
+ {...rest}
16
+ onClick={e => {
17
+ setIsFeedbackOpen(true);
18
+ onClick?.(e);
19
+ }}
20
+ data-cy="titan-chatbot-session-feedback-link"
21
+ >
22
+ {children}
23
+ </Link>
24
+ {isFeedbackOpen && <ChatbotSessionFeedbackModal onClose={handleFeedback} />}
25
+ </Fragment>
26
+ );
27
+ };
@@ -0,0 +1,95 @@
1
+ import { Button, ButtonToggle, Dialog, Flex, Text, Textarea } from '@servicetitan/anvil2';
2
+ import IconThumbDown from '@servicetitan/anvil2/assets/icons/material/round/thumb_down.svg';
3
+ import IconThumbUp from '@servicetitan/anvil2/assets/icons/material/round/thumb_up.svg';
4
+ import { provide, useDependencies } from '@servicetitan/react-ioc';
5
+ import { CHATBOT_UI_STORE_TOKEN, SessionFeedbackStore } from '@servicetitan/titan-chatbot-api';
6
+ import { observer } from 'mobx-react';
7
+ import { FC, useCallback } from 'react';
8
+
9
+ export const ChatbotSessionFeedbackModal: FC<{ onClose: () => void }> = provide({
10
+ singletons: [SessionFeedbackStore],
11
+ })(
12
+ observer(({ onClose }) => {
13
+ const [chatbotFeedbackStore, chatbotUiStore] = useDependencies(
14
+ SessionFeedbackStore,
15
+ CHATBOT_UI_STORE_TOKEN
16
+ );
17
+
18
+ const handleClose = useCallback(() => {
19
+ onClose();
20
+ }, [onClose]);
21
+
22
+ const handleSubmit = useCallback(() => {
23
+ chatbotUiStore.sendSessionFeedback(chatbotFeedbackStore.feedback);
24
+ onClose();
25
+ }, [chatbotUiStore, chatbotFeedbackStore, onClose]);
26
+
27
+ const handleThumbs = useCallback(
28
+ (isThumbsUp: boolean) => {
29
+ chatbotFeedbackStore.formState.$.thumbs.onChange(isThumbsUp ? 1 : -1);
30
+ },
31
+ [chatbotFeedbackStore]
32
+ );
33
+
34
+ return (
35
+ <Dialog
36
+ onClose={handleClose}
37
+ open
38
+ title="Give Feedback on Titan"
39
+ data-cy="titan-chatbot-session-feedback-modal"
40
+ >
41
+ <Dialog.Content>
42
+ <Flex direction="column" gap="2" className="m-block-start-6">
43
+ <Text>Was Titan able to help solve your problem?</Text>
44
+ <Flex direction="row" gap="4" alignItems="center">
45
+ <ButtonToggle
46
+ size="small"
47
+ aria-label="Thumbs Up"
48
+ title="Thumbs Up"
49
+ icon={IconThumbUp}
50
+ checked={chatbotFeedbackStore.isThumbsUp}
51
+ onClick={() => handleThumbs(true)}
52
+ data-cy="titan-chatbot-session-feedback-thumbs-up"
53
+ />
54
+ <ButtonToggle
55
+ size="small"
56
+ aria-label="Thumbs Down"
57
+ title="Thumbs Down"
58
+ icon={IconThumbDown}
59
+ checked={chatbotFeedbackStore.isThumbsDown}
60
+ onClick={() => handleThumbs(false)}
61
+ data-cy="titan-chatbot-session-feedback-thumbs-down"
62
+ />
63
+ </Flex>
64
+ <Textarea
65
+ className="m-block-start-4"
66
+ label="Tell us more"
67
+ rows={3}
68
+ value={chatbotFeedbackStore.formState.$.comment.value}
69
+ onChange={chatbotFeedbackStore.formState.$.comment.onChangeHandler}
70
+ data-cy="titan-chatbot-session-feedback-comment"
71
+ />
72
+ </Flex>
73
+ </Dialog.Content>
74
+ <Dialog.Footer>
75
+ <Flex direction="row" justifyContent="flex-end" gap="3">
76
+ <Button
77
+ onClick={handleClose}
78
+ data-cy="titan-chatbot-session-feedback-cancel"
79
+ >
80
+ Cancel
81
+ </Button>
82
+ <Button
83
+ onClick={handleSubmit}
84
+ appearance="primary"
85
+ disabled={!chatbotFeedbackStore.isValid}
86
+ data-cy="titan-chatbot-session-feedback-submit"
87
+ >
88
+ Submit Feedback
89
+ </Button>
90
+ </Flex>
91
+ </Dialog.Footer>
92
+ </Dialog>
93
+ );
94
+ })
95
+ );
@@ -0,0 +1,9 @@
1
+ import { AnvilProvider } from '@servicetitan/anvil2';
2
+ import { runChatbotFiltersSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
3
+ import { ChatFilters } from '../chatbot-filters';
4
+
5
+ describe('[ChatFilters]', () => {
6
+ runChatbotFiltersSharedTests(ChatFilters, component => (
7
+ <AnvilProvider>{component}</AnvilProvider>
8
+ ));
9
+ });
@@ -0,0 +1,58 @@
1
+ import { Chip, ChipProps } from '@servicetitan/anvil2';
2
+ import classNames from 'classnames';
3
+ import { FC, RefAttributes, forwardRef, useEffect, useImperativeHandle, useRef } from 'react';
4
+ import * as Styles from './chatbot-filter.module.css';
5
+
6
+ export const ChatbotFilterButton: FC<
7
+ RefAttributes<HTMLElement> & ChipProps & { count: number; open: boolean }
8
+ > = forwardRef<HTMLElement, ChipProps & { open: boolean; count: number }>(
9
+ ({ className, count, open, ...chipProps }, ref) => {
10
+ const buttonRef = useRef<HTMLElement | null>(null);
11
+
12
+ useImperativeHandle(ref, () => buttonRef.current!, []);
13
+
14
+ useEffect(() => {
15
+ // This is temporary solution until we have a proper filter button component, or it's replacement in Anvil2
16
+ const chip = buttonRef.current;
17
+ if (!chip) {
18
+ return;
19
+ }
20
+
21
+ // Ensure chip has a counter element
22
+ let counterEl: HTMLElement | null = chip.querySelector('.chip__counter');
23
+ if (!counterEl) {
24
+ counterEl = document.createElement('div');
25
+ counterEl.className = 'chip__counter';
26
+
27
+ chip.append(counterEl);
28
+ }
29
+ counterEl.textContent = count.toString();
30
+ counterEl.style.display = count > 0 ? 'flex' : 'none';
31
+
32
+ // Ensure chip has an icon element
33
+ const iconEl = chip.querySelector('.chip__icon');
34
+ if (!iconEl) {
35
+ const icon = document.createElement('img');
36
+ icon.className = 'chip__icon';
37
+ icon.src =
38
+ 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9ImN1cnJlbnRDb2xvciIgaGVpZ2h0PSIxZW0iIHdpZHRoPSIxZW0iIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTcuNDEgNy44NEwxMiAxMi40Mmw0LjU5LTQuNThMMTggOS4yNWwtNiA2LTYtNnoiPjwvcGF0aD48L3N2Zz4=';
39
+ chip.append(icon);
40
+ }
41
+ }, [count]);
42
+
43
+ return (
44
+ <Chip
45
+ ref={buttonRef}
46
+ className={classNames(
47
+ Styles.filterButton,
48
+ {
49
+ [Styles.filterButtonActive]: count > 0,
50
+ [Styles.filterButtonOpen]: open,
51
+ },
52
+ className
53
+ )}
54
+ {...chipProps}
55
+ />
56
+ );
57
+ }
58
+ );
@@ -0,0 +1,43 @@
1
+ @import '@servicetitan/tokens/dist/tokens.css';
2
+
3
+ .filterButton {
4
+ padding-inline: var(--size-1);
5
+ padding-block: var(--size-1);
6
+ border-radius: 0.375rem;
7
+ border: 1px solid
8
+ light-dark(var(--color-neutral-80, #949596), var(--color-neutral-100, #606162));
9
+ background-color: light-dark(
10
+ var(--color-neutral-0, #ffffff),
11
+ var(--color-neutral-400, #141414)
12
+ );
13
+ }
14
+
15
+ .filterButton:hover {
16
+ background-color: light-dark(#14141414, #ffffff14);
17
+ }
18
+
19
+ .filterButton > :global(.chip__counter) {
20
+ background-color: var(--color-purple-400, #6954c0);
21
+ color: var(--color-purple-100, #f1edff);
22
+ border-radius: 100%;
23
+ width: 1.25rem;
24
+ height: 1.25rem;
25
+ display: flex;
26
+ justify-content: center;
27
+ align-items: center;
28
+ margin-block: auto;
29
+ }
30
+
31
+ .filterButton.filterButtonActive {
32
+ background-color: var(--color-purple-100, #f1edff);
33
+ color: var(--color-purple-400, #6954c0);
34
+ border: 1px solid var(--color-purple-400, #6954c0);
35
+ }
36
+
37
+ .filterButton > :global(.chip__icon) {
38
+ transform: rotate(0deg);
39
+ }
40
+
41
+ .filterButton.filterButtonOpen > :global(.chip__icon) {
42
+ transform: rotate(180deg);
43
+ }
@@ -0,0 +1,5 @@
1
+ export const __esModule: true;
2
+ export const filterButton: string;
3
+ export const filterButtonActive: string;
4
+ export const filterButtonOpen: string;
5
+
@@ -0,0 +1,166 @@
1
+ import { Checkbox, Flex, Link, Popover, Text, TextField, useMergeRefs } from '@servicetitan/anvil2';
2
+ import { useDependencies } from '@servicetitan/react-ioc';
3
+ import { CHATBOT_UI_STORE_TOKEN, Models } from '@servicetitan/titan-chatbot-api';
4
+ import { observer } from 'mobx-react';
5
+ import { ChangeEvent, FC, Ref, useCallback, useEffect, useMemo, useRef, useState } from 'react';
6
+ import { ChatbotFilterButton } from './chatbot-filter-button';
7
+
8
+ interface IChatFilterProps {
9
+ filter: Models.IOption;
10
+ }
11
+
12
+ export const ChatFilter: FC<IChatFilterProps> = observer(({ filter }: IChatFilterProps) => {
13
+ const triggerRef = useRef<HTMLButtonElement>();
14
+ const [filterText, setFilterText] = useState('');
15
+ const [open, setOpen] = useState(false);
16
+ const [listMaxHeight, setListMaxHeight] = useState(400);
17
+ const [{ filterStore }] = useDependencies(CHATBOT_UI_STORE_TOKEN);
18
+ const filterLabel = filterStore.getFilterLabel(filter.displayName ?? filter.key).trim();
19
+ const selectedOptionsCount = filterStore.selectedOptions[filter.key]?.length ?? 0;
20
+
21
+ const allOptions = useMemo(() => {
22
+ return (
23
+ filter.subOptions?.map(filterSelectable => ({
24
+ text: filterStore.getFilterLabel(
25
+ filterSelectable.displayName ?? filterSelectable.key
26
+ ),
27
+ value: filterSelectable.key,
28
+ })) ?? []
29
+ );
30
+ }, [filterStore, filter.subOptions]);
31
+
32
+ const filteredOptions = useMemo(() => {
33
+ return allOptions.filter(
34
+ opt => opt.text && opt.text.toLowerCase().indexOf(filterText.toLowerCase()) > -1
35
+ );
36
+ }, [filterText, allOptions]);
37
+
38
+ useEffect(() => {
39
+ if (!triggerRef.current) {
40
+ return;
41
+ }
42
+ const triggerElement = triggerRef.current;
43
+ const boundingRect = triggerElement.getBoundingClientRect();
44
+ const headerFooterSize = 160;
45
+ setListMaxHeight(boundingRect.top - headerFooterSize);
46
+ }, []);
47
+
48
+ const handleToggle = () => {
49
+ setOpen(prev => !prev);
50
+ };
51
+
52
+ const handleCancel = (e: MouseEvent) => {
53
+ if (triggerRef.current?.contains(e.target as Node)) {
54
+ return;
55
+ }
56
+ setOpen(false);
57
+ };
58
+
59
+ const handleFilterChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
60
+ setFilterText(event.target.value);
61
+ }, []);
62
+
63
+ const handleItemChecked = useCallback(
64
+ (value: string, checked: boolean) => {
65
+ if (checked) {
66
+ filterStore.selectOption(filter.key, value);
67
+ } else {
68
+ filterStore.deselectOption(filter.key, value);
69
+ }
70
+ },
71
+ [filterStore, filter]
72
+ );
73
+
74
+ return (
75
+ <Popover
76
+ placement="top"
77
+ noPadding
78
+ maxHeight={listMaxHeight}
79
+ onOutsidePress={handleCancel}
80
+ open={open}
81
+ >
82
+ <Popover.Trigger>
83
+ {({ ref: popoverRef, ...props }) => {
84
+ const mergedRef = useMergeRefs([
85
+ popoverRef,
86
+ triggerRef as Ref<HTMLButtonElement>,
87
+ ]);
88
+ return (
89
+ <ChatbotFilterButton
90
+ {...props}
91
+ ref={mergedRef}
92
+ count={selectedOptionsCount}
93
+ open={open}
94
+ label={filterLabel}
95
+ onClick={handleToggle}
96
+ data-cy="titan-chatbot-filter-button"
97
+ />
98
+ );
99
+ }}
100
+ </Popover.Trigger>
101
+ <Popover.Content>
102
+ <Flex
103
+ direction="column"
104
+ className="p-4"
105
+ gap="4"
106
+ data-cy="titan-chatbot-filter-content"
107
+ >
108
+ <Flex>
109
+ <TextField
110
+ onChange={handleFilterChange}
111
+ value={filterText}
112
+ size="small"
113
+ placeholder="Search"
114
+ data-cy="titan-chatbot-filter-search"
115
+ />
116
+ </Flex>
117
+ {allOptions.length > 0 ? (
118
+ <Flex direction="column" gap="2" data-cy="titan-chatbot-filter-options">
119
+ {filteredOptions.map(option => (
120
+ <Checkbox
121
+ key={option.value}
122
+ label={option.text}
123
+ value={option.value}
124
+ checked={(
125
+ filterStore.selectedOptions[filter.key] || []
126
+ ).includes(option.value)}
127
+ onChange={(_, state) => {
128
+ handleItemChecked(
129
+ String(state?.value ?? ''),
130
+ !state?.checked
131
+ );
132
+ }}
133
+ />
134
+ ))}
135
+ </Flex>
136
+ ) : (
137
+ <Text className="ta-center" size="small" subdued>
138
+ No items available
139
+ </Text>
140
+ )}
141
+ <Flex direction="row" alignItems="baseline" gap="2">
142
+ <Text size="small">Select</Text>
143
+ <Text size="small">
144
+ <Link
145
+ appearance="primary"
146
+ onClick={() => filterStore.selectAll(filter.key)}
147
+ data-cy="titan-chatbot-filter-all"
148
+ >
149
+ All
150
+ </Link>
151
+ </Text>
152
+ <Text size="small">
153
+ <Link
154
+ appearance="primary"
155
+ onClick={() => filterStore.deselectAll(filter.key)}
156
+ data-cy="titan-chatbot-filter-none"
157
+ >
158
+ None
159
+ </Link>
160
+ </Text>
161
+ </Flex>
162
+ </Flex>
163
+ </Popover.Content>
164
+ </Popover>
165
+ );
166
+ });
@@ -0,0 +1,17 @@
1
+ import { Flex } from '@servicetitan/anvil2';
2
+ import { useDependencies } from '@servicetitan/react-ioc';
3
+ import { CHATBOT_UI_STORE_TOKEN } from '@servicetitan/titan-chatbot-api';
4
+ import { observer } from 'mobx-react';
5
+ import { FC } from 'react';
6
+ import { ChatFilter } from './chatbot-filter';
7
+
8
+ export const ChatFilters: FC<{ className?: string }> = observer(({ className }) => {
9
+ const [{ filterStore }] = useDependencies(CHATBOT_UI_STORE_TOKEN);
10
+ return filterStore.filters.length > 0 ? (
11
+ <Flex className={className} gap="2" data-cy="titan-chatbot-filters">
12
+ {filterStore.filters.map(filter => (
13
+ <ChatFilter key={filter.key} filter={filter} />
14
+ ))}
15
+ </Flex>
16
+ ) : null;
17
+ });
@@ -0,0 +1,9 @@
1
+ import { AnvilProvider } from '@servicetitan/anvil2';
2
+ import { runChatbotLinksSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
3
+ import { ChatbotLinks } from '../chatbot-links';
4
+
5
+ describe('[ChatbotLinks]', () => {
6
+ runChatbotLinksSharedTests(ChatbotLinks, component => (
7
+ <AnvilProvider>{component}</AnvilProvider>
8
+ ));
9
+ });
@@ -0,0 +1,9 @@
1
+ import { AnvilProvider } from '@servicetitan/anvil2';
2
+ import { runChatbotMessageAnswerReadonlySharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
3
+ import { ChatbotMessageAnswerReadonly } from '../chatbot-message-answer-readonly';
4
+
5
+ describe('[ChatbotMessageAnswerReadonly]', () => {
6
+ runChatbotMessageAnswerReadonlySharedTests(ChatbotMessageAnswerReadonly, component => (
7
+ <AnvilProvider>{component}</AnvilProvider>
8
+ ));
9
+ });
@@ -0,0 +1,9 @@
1
+ import { AnvilProvider } from '@servicetitan/anvil2';
2
+ import { runChatbotMessageAnswerSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
3
+ import { ChatbotMessageAnswer } from '../chatbot-message-answer';
4
+
5
+ describe('[ChatbotMessageAnswer]', () => {
6
+ runChatbotMessageAnswerSharedTests(ChatbotMessageAnswer, component => (
7
+ <AnvilProvider>{component}</AnvilProvider>
8
+ ));
9
+ });
@@ -0,0 +1,9 @@
1
+ import { AnvilProvider } from '@servicetitan/anvil2';
2
+ import { runChatbotMessageTypingSharedTests } from '@servicetitan/titan-chatbot-ui-cypress';
3
+ import { ChatbotMessageTyping } from '../chatbot-message-typing';
4
+
5
+ describe('[ChatbotMessageTyping]', () => {
6
+ runChatbotMessageTypingSharedTests(ChatbotMessageTyping, component => (
7
+ <AnvilProvider>{component}</AnvilProvider>
8
+ ));
9
+ });
@@ -0,0 +1,24 @@
1
+ @import '@servicetitan/tokens/dist/tokens.less';
2
+
3
+ .details [data-anv='details-summary'] {
4
+ padding-inline: var(--size-0);
5
+ }
6
+
7
+ ul.message-link-list {
8
+ margin-bottom: var(--size-0);
9
+ padding-inline-start: var(--size-2);
10
+ margin-block-start: var(--size-1);
11
+ line-height: 1.25em;
12
+ }
13
+
14
+ ul.message-link-list > li {
15
+ padding-left: var(--size-1);
16
+ }
17
+
18
+ .messageLink {
19
+ display: -webkit-box;
20
+ -webkit-line-clamp: 2;
21
+ -webkit-box-orient: vertical;
22
+ overflow: hidden;
23
+ text-overflow: ellipsis;
24
+ }
@@ -0,0 +1,5 @@
1
+ export const __esModule: true;
2
+ export const details: string;
3
+ export const messageLink: string;
4
+ export const messageLinkList: string;
5
+
@@ -0,0 +1,73 @@
1
+ import { Details, Link, Text } from '@servicetitan/anvil2';
2
+ import { Models } from '@servicetitan/titan-chatbot-api';
3
+ import { FC, useCallback, useState } from 'react';
4
+ import * as Styles from './chatbot-links.module.less';
5
+
6
+ interface ChatLinksProps {
7
+ seeMoreLabel: string;
8
+ seeLessLabel: string;
9
+ links: Models.ScoredUrl[];
10
+ onToggle?: () => void;
11
+ linkProps?: {
12
+ primary?: boolean;
13
+ className?: string;
14
+ };
15
+ }
16
+
17
+ export const ChatbotLinks: FC<ChatLinksProps> = ({
18
+ linkProps,
19
+ links,
20
+ onToggle,
21
+ seeLessLabel,
22
+ seeMoreLabel,
23
+ }) => {
24
+ const [linksCollapsed, setLinksCollapsed] = useState(true);
25
+
26
+ const handleToggleCollapsible = useCallback(() => {
27
+ setLinksCollapsed(!linksCollapsed);
28
+ setTimeout(() => {
29
+ onToggle?.();
30
+ }, 200);
31
+ }, [onToggle, linksCollapsed]);
32
+
33
+ if (!links.length) {
34
+ return null;
35
+ }
36
+ return (
37
+ <Details className={Styles.details}>
38
+ <Details.Summary>
39
+ <Link
40
+ appearance="secondary"
41
+ className="m-inline-start-2"
42
+ onClick={handleToggleCollapsible}
43
+ data-cy="titan-chatbot-links-more"
44
+ data-pendo="titan-chatbot-links-more"
45
+ >
46
+ {linksCollapsed ? seeMoreLabel : seeLessLabel}
47
+ </Link>
48
+ </Details.Summary>
49
+ <Details.Content data-cy="titan-chatbot-links-collapsible">
50
+ <ul className={Styles.messageLinkList}>
51
+ {links.map(u => (
52
+ <li key={u.url}>
53
+ <Text>
54
+ <Link
55
+ href={u.url}
56
+ target="_blank"
57
+ className={Styles.messageLink}
58
+ primary
59
+ data-cy="titan-chatbot-links-link"
60
+ data-pendo="titan-chatbot-links-link-secondary"
61
+ title={u.title ?? u.url}
62
+ {...linkProps}
63
+ >
64
+ {u.title ?? u.url}
65
+ </Link>
66
+ </Text>
67
+ </li>
68
+ ))}
69
+ </ul>
70
+ </Details.Content>
71
+ </Details>
72
+ );
73
+ };
@@ -0,0 +1,35 @@
1
+ import { Flex, Text } from '@servicetitan/anvil2';
2
+ import {
3
+ ChatMessageModelBase,
4
+ formatChatMessageDate,
5
+ getFirstName,
6
+ } from '@servicetitan/titan-chat-ui-common';
7
+ import { Models } from '@servicetitan/titan-chatbot-api';
8
+ import { observer } from 'mobx-react';
9
+ import { FC, useMemo } from 'react';
10
+ import { ChatbotMessageFeedback } from '../feedback/chatbot-message-feedback';
11
+
12
+ interface IChatbotMessageAgentFooterProps {
13
+ message: Pick<ChatMessageModelBase, 'participant' | 'timestamp' | 'data'>;
14
+ }
15
+
16
+ export const ChatbotMessageAgentFooter: FC<IChatbotMessageAgentFooterProps> = observer(
17
+ ({ message }) => {
18
+ const botMessage = useMemo(() => message.data as Models.IBotMessage, [message]);
19
+ const isBotMessage = Boolean(botMessage) && message.participant.isAgent;
20
+ const firstName = useMemo(
21
+ () => getFirstName(message.participant.name),
22
+ [message.participant.name]
23
+ );
24
+
25
+ return (
26
+ <Flex gap="4" justifyContent="space-between" alignItems="center">
27
+ <Text variant="eyebrow">
28
+ {message.participant.isAgent && `${firstName} • `}
29
+ {formatChatMessageDate(message.timestamp)}
30
+ </Text>
31
+ {isBotMessage && <ChatbotMessageFeedback botMessage={botMessage} />}
32
+ </Flex>
33
+ );
34
+ }
35
+ );