@servicetitan/titan-chat-ui 1.0.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 (244) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/assets/floating-chat-avatar.svg +16 -0
  3. package/dist/components/chat/__tests-cy__/chat-messages.test.d.ts +2 -0
  4. package/dist/components/chat/__tests-cy__/chat-messages.test.d.ts.map +1 -0
  5. package/dist/components/chat/__tests-cy__/chat-messages.test.js +28 -0
  6. package/dist/components/chat/__tests-cy__/chat-messages.test.js.map +1 -0
  7. package/dist/components/chat/__tests-cy__/chat.test.d.ts +2 -0
  8. package/dist/components/chat/__tests-cy__/chat.test.d.ts.map +1 -0
  9. package/dist/components/chat/__tests-cy__/chat.test.js +122 -0
  10. package/dist/components/chat/__tests-cy__/chat.test.js.map +1 -0
  11. package/dist/components/chat/chat-connecting.d.ts +7 -0
  12. package/dist/components/chat/chat-connecting.d.ts.map +1 -0
  13. package/dist/components/chat/chat-connecting.js +6 -0
  14. package/dist/components/chat/chat-connecting.js.map +1 -0
  15. package/dist/components/chat/chat-error.d.ts +3 -0
  16. package/dist/components/chat/chat-error.d.ts.map +1 -0
  17. package/dist/components/chat/chat-error.js +18 -0
  18. package/dist/components/chat/chat-error.js.map +1 -0
  19. package/dist/components/chat/chat-error.module.less +6 -0
  20. package/dist/components/chat/chat-input-file.d.ts +5 -0
  21. package/dist/components/chat/chat-input-file.d.ts.map +1 -0
  22. package/dist/components/chat/chat-input-file.js +43 -0
  23. package/dist/components/chat/chat-input-file.js.map +1 -0
  24. package/dist/components/chat/chat-input.d.ts +5 -0
  25. package/dist/components/chat/chat-input.d.ts.map +1 -0
  26. package/dist/components/chat/chat-input.js +94 -0
  27. package/dist/components/chat/chat-input.js.map +1 -0
  28. package/dist/components/chat/chat-input.module.less +11 -0
  29. package/dist/components/chat/chat-message-template-agent.d.ts +4 -0
  30. package/dist/components/chat/chat-message-template-agent.d.ts.map +1 -0
  31. package/dist/components/chat/chat-message-template-agent.js +14 -0
  32. package/dist/components/chat/chat-message-template-agent.js.map +1 -0
  33. package/dist/components/chat/chat-message-template-user.d.ts +4 -0
  34. package/dist/components/chat/chat-message-template-user.d.ts.map +1 -0
  35. package/dist/components/chat/chat-message-template-user.js +16 -0
  36. package/dist/components/chat/chat-message-template-user.js.map +1 -0
  37. package/dist/components/chat/chat-message-typing.d.ts +3 -0
  38. package/dist/components/chat/chat-message-typing.d.ts.map +1 -0
  39. package/dist/components/chat/chat-message-typing.js +15 -0
  40. package/dist/components/chat/chat-message-typing.js.map +1 -0
  41. package/dist/components/chat/chat-message.d.ts +12 -0
  42. package/dist/components/chat/chat-message.d.ts.map +1 -0
  43. package/dist/components/chat/chat-message.js +60 -0
  44. package/dist/components/chat/chat-message.js.map +1 -0
  45. package/dist/components/chat/chat-messages.d.ts +7 -0
  46. package/dist/components/chat/chat-messages.d.ts.map +1 -0
  47. package/dist/components/chat/chat-messages.js +12 -0
  48. package/dist/components/chat/chat-messages.js.map +1 -0
  49. package/dist/components/chat/chat-notifications.d.ts +5 -0
  50. package/dist/components/chat/chat-notifications.d.ts.map +1 -0
  51. package/dist/components/chat/chat-notifications.js +12 -0
  52. package/dist/components/chat/chat-notifications.js.map +1 -0
  53. package/dist/components/chat/chat-timer.d.ts +3 -0
  54. package/dist/components/chat/chat-timer.d.ts.map +1 -0
  55. package/dist/components/chat/chat-timer.js +18 -0
  56. package/dist/components/chat/chat-timer.js.map +1 -0
  57. package/dist/components/chat/chat-timer.module.less +5 -0
  58. package/dist/components/chat/chat.d.ts +8 -0
  59. package/dist/components/chat/chat.d.ts.map +1 -0
  60. package/dist/components/chat/chat.js +28 -0
  61. package/dist/components/chat/chat.js.map +1 -0
  62. package/dist/components/common/multiline-text.d.ts +8 -0
  63. package/dist/components/common/multiline-text.d.ts.map +1 -0
  64. package/dist/components/common/multiline-text.js +12 -0
  65. package/dist/components/common/multiline-text.js.map +1 -0
  66. package/dist/components/common/multiline-text.module.less +9 -0
  67. package/dist/components/message-content/message-content-file.d.ts +8 -0
  68. package/dist/components/message-content/message-content-file.d.ts.map +1 -0
  69. package/dist/components/message-content/message-content-file.js +11 -0
  70. package/dist/components/message-content/message-content-file.js.map +1 -0
  71. package/dist/components/message-content/message-content-text.d.ts +8 -0
  72. package/dist/components/message-content/message-content-text.d.ts.map +1 -0
  73. package/dist/components/message-content/message-content-text.js +7 -0
  74. package/dist/components/message-content/message-content-text.js.map +1 -0
  75. package/dist/components/messages/__tests-cy__/message-agent.test.d.ts +2 -0
  76. package/dist/components/messages/__tests-cy__/message-agent.test.d.ts.map +1 -0
  77. package/dist/components/messages/__tests-cy__/message-agent.test.js +89 -0
  78. package/dist/components/messages/__tests-cy__/message-agent.test.js.map +1 -0
  79. package/dist/components/messages/__tests-cy__/message-system.test.d.ts +2 -0
  80. package/dist/components/messages/__tests-cy__/message-system.test.d.ts.map +1 -0
  81. package/dist/components/messages/__tests-cy__/message-system.test.js +20 -0
  82. package/dist/components/messages/__tests-cy__/message-system.test.js.map +1 -0
  83. package/dist/components/messages/__tests-cy__/message-timeout.test.d.ts +2 -0
  84. package/dist/components/messages/__tests-cy__/message-timeout.test.d.ts.map +1 -0
  85. package/dist/components/messages/__tests-cy__/message-timeout.test.js +32 -0
  86. package/dist/components/messages/__tests-cy__/message-timeout.test.js.map +1 -0
  87. package/dist/components/messages/__tests-cy__/message-typing.test.d.ts +2 -0
  88. package/dist/components/messages/__tests-cy__/message-typing.test.d.ts.map +1 -0
  89. package/dist/components/messages/__tests-cy__/message-typing.test.js +49 -0
  90. package/dist/components/messages/__tests-cy__/message-typing.test.js.map +1 -0
  91. package/dist/components/messages/__tests-cy__/message-user.test.d.ts +2 -0
  92. package/dist/components/messages/__tests-cy__/message-user.test.d.ts.map +1 -0
  93. package/dist/components/messages/__tests-cy__/message-user.test.js +33 -0
  94. package/dist/components/messages/__tests-cy__/message-user.test.js.map +1 -0
  95. package/dist/components/messages/message-agent.d.ts +12 -0
  96. package/dist/components/messages/message-agent.d.ts.map +1 -0
  97. package/dist/components/messages/message-agent.js +18 -0
  98. package/dist/components/messages/message-agent.js.map +1 -0
  99. package/dist/components/messages/message-agent.module.less +59 -0
  100. package/dist/components/messages/message-avatar.d.ts +9 -0
  101. package/dist/components/messages/message-avatar.d.ts.map +1 -0
  102. package/dist/components/messages/message-avatar.js +14 -0
  103. package/dist/components/messages/message-avatar.js.map +1 -0
  104. package/dist/components/messages/message-avatar.module.less +26 -0
  105. package/dist/components/messages/message-footer.d.ts +7 -0
  106. package/dist/components/messages/message-footer.d.ts.map +1 -0
  107. package/dist/components/messages/message-footer.js +7 -0
  108. package/dist/components/messages/message-footer.js.map +1 -0
  109. package/dist/components/messages/message-system.d.ts +8 -0
  110. package/dist/components/messages/message-system.d.ts.map +1 -0
  111. package/dist/components/messages/message-system.js +12 -0
  112. package/dist/components/messages/message-system.js.map +1 -0
  113. package/dist/components/messages/message-system.module.less +26 -0
  114. package/dist/components/messages/message-timeout.d.ts +8 -0
  115. package/dist/components/messages/message-timeout.d.ts.map +1 -0
  116. package/dist/components/messages/message-timeout.js +16 -0
  117. package/dist/components/messages/message-timeout.js.map +1 -0
  118. package/dist/components/messages/message-typing.d.ts +8 -0
  119. package/dist/components/messages/message-typing.d.ts.map +1 -0
  120. package/dist/components/messages/message-typing.js +10 -0
  121. package/dist/components/messages/message-typing.js.map +1 -0
  122. package/dist/components/messages/message-typing.module.less +40 -0
  123. package/dist/components/messages/message-user.d.ts +9 -0
  124. package/dist/components/messages/message-user.d.ts.map +1 -0
  125. package/dist/components/messages/message-user.js +13 -0
  126. package/dist/components/messages/message-user.js.map +1 -0
  127. package/dist/components/messages/message-user.module.less +35 -0
  128. package/dist/components/messages/use-avatar-props.d.ts +4 -0
  129. package/dist/components/messages/use-avatar-props.d.ts.map +1 -0
  130. package/dist/components/messages/use-avatar-props.js +12 -0
  131. package/dist/components/messages/use-avatar-props.js.map +1 -0
  132. package/dist/index.d.ts +12 -0
  133. package/dist/index.d.ts.map +1 -0
  134. package/dist/index.js +12 -0
  135. package/dist/index.js.map +1 -0
  136. package/dist/models/chat-customizations.d.ts +29 -0
  137. package/dist/models/chat-customizations.d.ts.map +1 -0
  138. package/dist/models/chat-customizations.js +2 -0
  139. package/dist/models/chat-customizations.js.map +1 -0
  140. package/dist/models/component.d.ts +4 -0
  141. package/dist/models/component.d.ts.map +1 -0
  142. package/dist/models/component.js +2 -0
  143. package/dist/models/component.js.map +1 -0
  144. package/dist/models/index.d.ts +3 -0
  145. package/dist/models/index.d.ts.map +1 -0
  146. package/dist/models/index.js +3 -0
  147. package/dist/models/index.js.map +1 -0
  148. package/dist/models/support-chat.d.ts +66 -0
  149. package/dist/models/support-chat.d.ts.map +1 -0
  150. package/dist/models/support-chat.js +28 -0
  151. package/dist/models/support-chat.js.map +1 -0
  152. package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts +65 -0
  153. package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts.map +1 -0
  154. package/dist/stores/__mocks-cy__/chat-ui.store.mock.js +268 -0
  155. package/dist/stores/__mocks-cy__/chat-ui.store.mock.js.map +1 -0
  156. package/dist/stores/chat-input.store.d.ts +10 -0
  157. package/dist/stores/chat-input.store.d.ts.map +1 -0
  158. package/dist/stores/chat-input.store.js +46 -0
  159. package/dist/stores/chat-input.store.js.map +1 -0
  160. package/dist/stores/chat-ui-backend-echo.store.d.ts +13 -0
  161. package/dist/stores/chat-ui-backend-echo.store.d.ts.map +1 -0
  162. package/dist/stores/chat-ui-backend-echo.store.js +111 -0
  163. package/dist/stores/chat-ui-backend-echo.store.js.map +1 -0
  164. package/dist/stores/chat-ui-backend.store.d.ts +6 -0
  165. package/dist/stores/chat-ui-backend.store.d.ts.map +1 -0
  166. package/dist/stores/chat-ui-backend.store.js +3 -0
  167. package/dist/stores/chat-ui-backend.store.js.map +1 -0
  168. package/dist/stores/chat-ui.store.d.ts +142 -0
  169. package/dist/stores/chat-ui.store.d.ts.map +1 -0
  170. package/dist/stores/chat-ui.store.js +679 -0
  171. package/dist/stores/chat-ui.store.js.map +1 -0
  172. package/dist/stores/index.d.ts +3 -0
  173. package/dist/stores/index.d.ts.map +1 -0
  174. package/dist/stores/index.js +3 -0
  175. package/dist/stores/index.js.map +1 -0
  176. package/dist/utils/text-utils.d.ts +11 -0
  177. package/dist/utils/text-utils.d.ts.map +1 -0
  178. package/dist/utils/text-utils.js +82 -0
  179. package/dist/utils/text-utils.js.map +1 -0
  180. package/package.json +52 -0
  181. package/src/assets/floating-chat-avatar.svg +16 -0
  182. package/src/components/chat/__tests-cy__/chat-messages.test.tsx +36 -0
  183. package/src/components/chat/__tests-cy__/chat.test.tsx +156 -0
  184. package/src/components/chat/chat-connecting.tsx +23 -0
  185. package/src/components/chat/chat-error.module.less +6 -0
  186. package/src/components/chat/chat-error.module.less.d.ts +3 -0
  187. package/src/components/chat/chat-error.tsx +39 -0
  188. package/src/components/chat/chat-input-file.tsx +68 -0
  189. package/src/components/chat/chat-input.module.less +11 -0
  190. package/src/components/chat/chat-input.module.less.d.ts +3 -0
  191. package/src/components/chat/chat-input.tsx +143 -0
  192. package/src/components/chat/chat-message-template-agent.tsx +26 -0
  193. package/src/components/chat/chat-message-template-user.tsx +46 -0
  194. package/src/components/chat/chat-message-typing.tsx +19 -0
  195. package/src/components/chat/chat-message.tsx +78 -0
  196. package/src/components/chat/chat-messages.tsx +23 -0
  197. package/src/components/chat/chat-notifications.tsx +19 -0
  198. package/src/components/chat/chat-timer.module.less +5 -0
  199. package/src/components/chat/chat-timer.module.less.d.ts +3 -0
  200. package/src/components/chat/chat-timer.tsx +35 -0
  201. package/src/components/chat/chat.tsx +55 -0
  202. package/src/components/common/multiline-text.module.less +9 -0
  203. package/src/components/common/multiline-text.module.less.d.ts +3 -0
  204. package/src/components/common/multiline-text.tsx +30 -0
  205. package/src/components/message-content/message-content-file.tsx +27 -0
  206. package/src/components/message-content/message-content-text.tsx +12 -0
  207. package/src/components/messages/__tests-cy__/message-agent.test.tsx +155 -0
  208. package/src/components/messages/__tests-cy__/message-system.test.tsx +33 -0
  209. package/src/components/messages/__tests-cy__/message-timeout.test.tsx +38 -0
  210. package/src/components/messages/__tests-cy__/message-typing.test.tsx +58 -0
  211. package/src/components/messages/__tests-cy__/message-user.test.tsx +52 -0
  212. package/src/components/messages/message-agent.module.less +59 -0
  213. package/src/components/messages/message-agent.module.less.d.ts +9 -0
  214. package/src/components/messages/message-agent.tsx +62 -0
  215. package/src/components/messages/message-avatar.module.less +26 -0
  216. package/src/components/messages/message-avatar.module.less.d.ts +5 -0
  217. package/src/components/messages/message-avatar.tsx +33 -0
  218. package/src/components/messages/message-footer.tsx +17 -0
  219. package/src/components/messages/message-system.module.less +26 -0
  220. package/src/components/messages/message-system.module.less.d.ts +5 -0
  221. package/src/components/messages/message-system.tsx +35 -0
  222. package/src/components/messages/message-timeout.tsx +42 -0
  223. package/src/components/messages/message-typing.module.less +40 -0
  224. package/src/components/messages/message-typing.module.less.d.ts +5 -0
  225. package/src/components/messages/message-typing.tsx +25 -0
  226. package/src/components/messages/message-user.module.less +35 -0
  227. package/src/components/messages/message-user.module.less.d.ts +7 -0
  228. package/src/components/messages/message-user.tsx +49 -0
  229. package/src/components/messages/use-avatar-props.tsx +17 -0
  230. package/src/cypress.d.ts +10 -0
  231. package/src/index.ts +11 -0
  232. package/src/models/chat-customizations.ts +34 -0
  233. package/src/models/component.ts +3 -0
  234. package/src/models/index.ts +2 -0
  235. package/src/models/support-chat.ts +84 -0
  236. package/src/stores/__mocks-cy__/chat-ui.store.mock.ts +105 -0
  237. package/src/stores/chat-input.store.ts +25 -0
  238. package/src/stores/chat-ui-backend-echo.store.ts +94 -0
  239. package/src/stores/chat-ui-backend.store.ts +10 -0
  240. package/src/stores/chat-ui.store.ts +537 -0
  241. package/src/stores/index.ts +10 -0
  242. package/src/utils/text-utils.ts +93 -0
  243. package/tsconfig.json +15 -0
  244. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,3 @@
1
+ export { CHAT_UI_STORE_TOKEN, IChatUiStore, ChatUiStore, ChatUiEvent, symbolUser, symbolAgent, ChatUiEventListener, } from './chat-ui.store';
2
+ export { CHAT_UI_BACKEND_STORE_TOKEN, IChatUiBackendStore } from './chat-ui-backend.store';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,WAAW,EACX,mBAAmB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { CHAT_UI_STORE_TOKEN, ChatUiStore, ChatUiEvent, symbolUser, symbolAgent, } from './chat-ui.store';
2
+ export { CHAT_UI_BACKEND_STORE_TOKEN } from './chat-ui-backend.store';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/stores/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,mBAAmB,EAEnB,WAAW,EACX,WAAW,EACX,UAAU,EACV,WAAW,GAEd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,2BAA2B,EAAuB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare function formatChatMessageDate(date: Date): string;
2
+ export declare const getFirstName: (name: string) => string;
3
+ export declare const getNameInitials: (name: string) => string;
4
+ export declare const getNameInitialsFirst: (name: string) => string;
5
+ export declare const extractFilenameAndExt: (fileName: string) => [string, string];
6
+ export declare const ellipsisText: (text: string, lineLength: number, linesCount: number, lastLineLength?: number) => {
7
+ lines: string[];
8
+ isCut: boolean;
9
+ };
10
+ export declare function extractContentFromHtml(html: string): string;
11
+ //# sourceMappingURL=text-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-utils.d.ts","sourceRoot":"","sources":["../../src/utils/text-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,UAK/C;AAED,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAG3C,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,MAAM,MAAM,KAAG,MAO9C,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,MAGnD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,UAAU,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,CASvE,CAAC;AAEF,eAAO,MAAM,YAAY,GACrB,MAAM,MAAM,EACZ,YAAY,MAAM,EAClB,YAAY,MAAM,EAClB,iBAAgB,MAAmB,KACpC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAgCnC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,UAgBlD"}
@@ -0,0 +1,82 @@
1
+ export function formatChatMessageDate(date) {
2
+ return date.toLocaleTimeString('en-US', {
3
+ hour: '2-digit',
4
+ minute: '2-digit',
5
+ });
6
+ }
7
+ export const getFirstName = (name) => {
8
+ const parts = name.split(' ');
9
+ return parts[0];
10
+ };
11
+ export const getNameInitials = (name) => {
12
+ const parts = name.split(' ');
13
+ return parts
14
+ .filter(Boolean)
15
+ .splice(0, 2)
16
+ .map(p => p[0].toUpperCase())
17
+ .join('');
18
+ };
19
+ export const getNameInitialsFirst = (name) => {
20
+ const initials = getNameInitials(name);
21
+ return initials.length > 0 ? initials[0] : '';
22
+ };
23
+ export const extractFilenameAndExt = (fileName) => {
24
+ const lastIndex = fileName.lastIndexOf('.');
25
+ if (lastIndex === -1) {
26
+ return [fileName, ''];
27
+ }
28
+ return [
29
+ fileName.substring(0, lastIndex) + '.',
30
+ fileName.substring(lastIndex + 1, fileName.length),
31
+ ];
32
+ };
33
+ export const ellipsisText = (text, lineLength, linesCount, lastLineLength = lineLength) => {
34
+ let lines = text.split('\n').map(l => l.trim());
35
+ let isCut = false;
36
+ let charsLeft = lineLength * linesCount - lastLineLength;
37
+ let linesLeft = linesCount;
38
+ for (let i = 0; i < lines.length; i++) {
39
+ let line = lines[i];
40
+ let linesInRow = Math.trunc(line.length / lineLength);
41
+ if (line.length % lineLength > 0) {
42
+ linesInRow++;
43
+ }
44
+ if (linesInRow === 0) {
45
+ linesInRow = 1;
46
+ }
47
+ linesLeft -= linesInRow;
48
+ line = line.slice(0, charsLeft);
49
+ lines[i] = line;
50
+ charsLeft = charsLeft - Math.max(lineLength, line.length);
51
+ if (charsLeft <= 0 || linesLeft <= 0) {
52
+ isCut = line.length >= lineLength - lastLineLength || i < lines.length - 1;
53
+ lines = lines.slice(0, i + 1);
54
+ if (line.length >= lineLength - lastLineLength) {
55
+ lines[i] = lines[i] + '...';
56
+ }
57
+ break;
58
+ }
59
+ }
60
+ return {
61
+ isCut,
62
+ lines,
63
+ };
64
+ };
65
+ export function extractContentFromHtml(html) {
66
+ const span = document.createElement('span');
67
+ span.innerHTML = html;
68
+ function getTextLoop(element) {
69
+ const texts = [];
70
+ Array.from(element.childNodes).forEach(node => {
71
+ if (node.nodeType === Node.TEXT_NODE && node.textContent) {
72
+ texts.push(node.textContent.trim());
73
+ }
74
+ else {
75
+ texts.push(...getTextLoop(node));
76
+ }
77
+ });
78
+ return texts;
79
+ }
80
+ return getTextLoop(span).join(' ');
81
+ }
82
+ //# sourceMappingURL=text-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-utils.js","sourceRoot":"","sources":["../../src/utils/text-utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@servicetitan/titan-chat-ui",
3
+ "version": "1.0.1",
4
+ "description": "Chat experience UI package",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/servicetitan/titan-chatbot-client",
8
+ "directory": "packages/titan-chat-ui"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "typings": "./dist/index.d.ts",
12
+ "scripts": {
13
+ "publish:local": "yalc publish",
14
+ "push:local": "yalc push"
15
+ },
16
+ "dependencies": {
17
+ "lodash": "4.17.21",
18
+ "nanoid": "^5.1.5"
19
+ },
20
+ "peerDependencies": {
21
+ "@servicetitan/confirm": ">=27",
22
+ "@servicetitan/culture": ">=27",
23
+ "@servicetitan/design-system": "^14",
24
+ "@servicetitan/form": ">=27",
25
+ "@servicetitan/form-state": ">=27",
26
+ "@servicetitan/react-ioc": ">=24",
27
+ "@servicetitan/skeleton": ">=8",
28
+ "@servicetitan/tokens": ">=12.9.0",
29
+ "axios": ">=0.28.0",
30
+ "classnames": ">=2.3.0",
31
+ "formstate": ">=2.0.0",
32
+ "mobx": ">=6",
33
+ "mobx-react": ">=9",
34
+ "mobx-utils": ">=6",
35
+ "react": "^18",
36
+ "react-dom": "^18"
37
+ },
38
+ "devDependencies": {
39
+ "cypress": "^14.3.2"
40
+ },
41
+ "keywords": [
42
+ "ServiceTitan"
43
+ ],
44
+ "author": "Alexander Yarmolchuk",
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "cli": {
49
+ "webpack": false
50
+ },
51
+ "gitHead": "88893dad270ac1700a910152b4375b902ba5ad99"
52
+ }
@@ -0,0 +1,16 @@
1
+ <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M24 48C37.2548 48 48 37.2548 48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24C0 37.2548 10.7452 48 24 48Z" fill="url(#paint0_linear_11705_2385)"/>
3
+ <path d="M36 26.8983V33.0158C36 33.7621 35.6 34.4019 34.9333 34.7351C33.36 35.5081 30.36 37.0141 28.2667 38.0537C27.5067 38.4136 26.8667 38.7334 26.4533 38.96C26.4 38.9867 26.3333 39 26.28 39H26.2667C26.2667 39 26.2267 39 26.2 38.9867C26.0267 38.9467 25.9067 38.7868 25.9067 38.6135V31.4831C25.9067 31.2698 26.0533 31.0699 26.2667 31.0299H27.4667C30.3333 31.0299 32.6667 28.7109 32.6667 25.832V25.5655C32.6667 22.7 30.3333 20.3676 27.4667 20.3676H20.5333C17.6667 20.3676 15.3333 22.7 15.3333 25.5655V25.832C15.3333 28.7109 17.6667 31.0299 20.5333 31.0299H22.08C22.2933 31.0699 22.44 31.2698 22.44 31.4697V38.5868C22.44 38.7468 22.3467 38.88 22.2 38.9334C22.1867 38.9467 22.16 38.96 22.1333 38.96C22.0667 38.9867 21.9733 38.9733 21.8933 38.92L20.9333 38.4536L19.2933 37.6406L13.0667 34.5351C12.4133 34.2153 12 33.5489 12 32.8292V27.0182C12 25.6588 12.24 24.326 12.6667 23.0865C12.72 22.9399 12.7733 22.7533 12.8267 22.6067C12.8267 22.6067 12.8311 22.5978 12.84 22.58C14.1467 19.3147 16.8 16.769 20.12 15.6362C20.2133 15.6095 20.3067 15.5695 20.4 15.5562C21.32 15.2497 22.28 15.0897 23.28 15.0364C23.6133 15.0098 23.9333 15.0098 24.2667 15.0098C25.5067 15.0364 26.6933 15.223 27.7867 15.6095C27.8133 15.6228 27.84 15.6228 27.8667 15.6362C29.64 16.2226 31.2 17.1955 32.4933 18.4883C33.6533 19.6345 34.5733 21.034 35.2 22.58C35.7067 23.9128 36 25.3789 36 26.8983Z" fill="white"/>
4
+ <path d="M40 23.4735V30.6572C40 30.8838 39.8267 31.057 39.6 31.057H37.84V26.8854C37.84 25.366 37.5867 23.8866 37.1467 22.5272V20.6479C37.1467 19.7816 36.84 18.9819 36.48 18.1956C36.3867 17.9824 36.3333 17.7425 36.3333 17.4892C36.3333 16.5696 37.08 15.8232 38 15.8232C38.92 15.8232 39.6667 16.5696 39.6667 17.4892C39.6667 17.7425 39.6 17.9824 39.5067 18.1956C39.1333 18.9953 38.8133 19.8216 38.8133 20.7146V23.0603H39.6C39.8267 23.0603 40 23.2469 40 23.4735Z" fill="white"/>
5
+ <path d="M11.6667 17.4756C11.6667 17.7288 11.6133 17.9687 11.52 18.1819C11.16 18.9683 10.8533 19.768 10.8533 20.6343V22.7401C10.4133 24.0862 10.16 25.5256 10.16 27.005V31.0434H8.4C8.17333 31.0434 8 30.8701 8 30.6435V23.4598C8 23.2332 8.17333 23.0466 8.4 23.0466H9.18667V20.7009C9.18667 19.8079 8.86667 18.9816 8.49333 18.1819C8.4 17.9687 8.33333 17.7288 8.33333 17.4756C8.33333 16.5559 9.08 15.8096 10 15.8096C10.92 15.8096 11.6667 16.5559 11.6667 17.4756Z" fill="white"/>
6
+ <path d="M19.0666 27.2987C19.8987 27.2987 20.5732 26.6244 20.5732 25.7926C20.5732 24.9609 19.8987 24.2866 19.0666 24.2866C18.2345 24.2866 17.5599 24.9609 17.5599 25.7926C17.5599 26.6244 18.2345 27.2987 19.0666 27.2987Z" fill="white"/>
7
+ <path d="M24.0002 27.2987C24.8323 27.2987 25.5068 26.6244 25.5068 25.7926C25.5068 24.9609 24.8323 24.2866 24.0002 24.2866C23.168 24.2866 22.4935 24.9609 22.4935 25.7926C22.4935 26.6244 23.168 27.2987 24.0002 27.2987Z" fill="white"/>
8
+ <path d="M28.9334 27.2851C29.7582 27.2851 30.4268 26.6167 30.4268 25.7923C30.4268 24.9679 29.7582 24.2996 28.9334 24.2996C28.1087 24.2996 27.4401 24.9679 27.4401 25.7923C27.4401 26.6167 28.1087 27.2851 28.9334 27.2851Z" fill="white"/>
9
+ <path d="M27.7071 7.87964C27.8537 7.45315 27.5204 7 27.0671 7H24L22.6667 10.3333L21.3333 7H20.9337C20.4671 7 20.1471 7.43982 20.2937 7.87964L22.1204 13.3441C22.4671 13.2908 22.8137 13.2641 23.1737 13.2508C23.5604 13.2108 23.9204 13.2108 24.3071 13.2108C24.8404 13.2241 25.3604 13.2641 25.8804 13.3441L27.7071 7.87964Z" fill="white"/>
10
+ <defs>
11
+ <linearGradient id="paint0_linear_11705_2385" x1="24.0002" y1="0" x2="24.0002" y2="48" gradientUnits="userSpaceOnUse">
12
+ <stop offset="0.145833" stop-color="#8473E6"/>
13
+ <stop offset="0.942708" stop-color="#2671EE"/>
14
+ </linearGradient>
15
+ </defs>
16
+ </svg>
@@ -0,0 +1,36 @@
1
+ import { Provider } from '@servicetitan/react-ioc';
2
+ import { mount } from 'cypress/react';
3
+ import { CHAT_UI_STORE_TOKEN } from '../../../stores';
4
+ import { ChatUiStoreMock } from '../../../stores/__mocks-cy__/chat-ui.store.mock';
5
+ import { ChatMessages } from '../chat-messages';
6
+
7
+ describe('[ChatMessages]', () => {
8
+ let storeMock: ChatUiStoreMock;
9
+
10
+ beforeEach(() => {
11
+ cy.viewport(780, 600);
12
+ cy.clock(new Date('2023-10-01T10:10:00Z').getTime());
13
+ storeMock = new ChatUiStoreMock();
14
+ });
15
+
16
+ const render = () => {
17
+ return mount(
18
+ <Provider
19
+ singletons={[
20
+ {
21
+ provide: CHAT_UI_STORE_TOKEN,
22
+ useValue: storeMock,
23
+ },
24
+ ]}
25
+ >
26
+ <ChatMessages />
27
+ </Provider>
28
+ );
29
+ };
30
+
31
+ it('should render default chat', () => {
32
+ render();
33
+ cy.getCy('titan-chat-messages').should('be.visible');
34
+ cy.getCy2('chat-message-normal').should('have.length', 2);
35
+ });
36
+ });
@@ -0,0 +1,156 @@
1
+ import { Container, provide, useDependencies } from '@servicetitan/react-ioc';
2
+ import { mount } from 'cypress/react';
3
+ import { useEffect } from 'react';
4
+ import { ChatParticipantIcon } from '../../../models';
5
+ import {
6
+ CHAT_UI_BACKEND_STORE_TOKEN,
7
+ CHAT_UI_STORE_TOKEN,
8
+ ChatUiStore,
9
+ IChatUiBackendStore,
10
+ IChatUiStore,
11
+ } from '../../../stores';
12
+ import { ChatUiBackendEchoStore } from '../../../stores/chat-ui-backend-echo.store';
13
+ import { Chat } from '../chat';
14
+
15
+ const initContainer = () => {
16
+ const rootContainer = new Container();
17
+ const container = new Container();
18
+ container.parent = rootContainer;
19
+ container.bind<IChatUiStore>(CHAT_UI_STORE_TOKEN).to(ChatUiStore).inSingletonScope();
20
+ container
21
+ .bind<IChatUiBackendStore>(CHAT_UI_BACKEND_STORE_TOKEN)
22
+ .to(ChatUiBackendEchoStore)
23
+ .inSingletonScope();
24
+ return container;
25
+ };
26
+
27
+ describe('[Chat]', () => {
28
+ let container: Container;
29
+ let chatUiStore: IChatUiStore;
30
+ let chatUiBackendStore: ChatUiBackendEchoStore;
31
+
32
+ beforeEach(() => {
33
+ container = initContainer();
34
+ chatUiStore = container.get<IChatUiStore>(CHAT_UI_STORE_TOKEN);
35
+ chatUiBackendStore = container.get<ChatUiBackendEchoStore>(CHAT_UI_BACKEND_STORE_TOKEN);
36
+ cy.viewport(780, 800);
37
+ cy.clock(Date.parse('2023-10-01T00:00:00Z'));
38
+ });
39
+
40
+ const render = () => {
41
+ const ChatWrapper = provide({
42
+ singletons: [
43
+ {
44
+ provide: CHAT_UI_STORE_TOKEN,
45
+ useValue: chatUiStore,
46
+ },
47
+ {
48
+ provide: CHAT_UI_BACKEND_STORE_TOKEN,
49
+ useValue: chatUiBackendStore,
50
+ },
51
+ ],
52
+ })(() => {
53
+ const [chatUiStore, chatUiBackendStore] = useDependencies(
54
+ CHAT_UI_STORE_TOKEN,
55
+ CHAT_UI_BACKEND_STORE_TOKEN
56
+ );
57
+ useEffect(() => {
58
+ const init = async () => {
59
+ chatUiBackendStore.subscribe();
60
+ await chatUiStore.run({
61
+ agentName: 'EchoBot',
62
+ agentIcon: ChatParticipantIcon.Bot,
63
+ });
64
+ };
65
+ init().then(() => {});
66
+ return () => chatUiBackendStore.unsubscribe();
67
+ }, [chatUiStore, chatUiBackendStore]);
68
+ return <Chat className="h-100vh max-h-100vh" />;
69
+ });
70
+
71
+ cy.spy(chatUiStore, 'run').as('runSpy');
72
+ mount(<ChatWrapper />);
73
+
74
+ cy.getCy('titan-chat-connecting').should('be.visible');
75
+ cy.tick(1000);
76
+ return cy.wrap(
77
+ new Promise(resolve => {
78
+ cy.get('@runSpy')
79
+ .should('have.been.calledOnce')
80
+ .then((invocation: any) => {
81
+ const initPromise = invocation.firstCall.returnValue as ReturnType<
82
+ IChatUiStore['run']
83
+ >;
84
+ initPromise.then(resolve);
85
+ });
86
+ })
87
+ );
88
+ };
89
+
90
+ const ask = (message: string) => {
91
+ cy.getCy('titan-chat-input').type(`${message}{enter}`);
92
+ };
93
+
94
+ it('should render default chat', () => {
95
+ render().then(() => {
96
+ cy.getCy('titan-chat-messages').should('be.visible');
97
+ cy.getCy('chat-message-agent')
98
+ .should('have.length', 1)
99
+ .should('be.visible')
100
+ .should(
101
+ 'contain.text',
102
+ 'Hi there! I’m Titan, an AI chatbot powered by Titan Intelligence.'
103
+ );
104
+ cy.getCy('titan-chat-notifications').should('exist');
105
+ cy.getCy('titan-chat-send').should('be.visible').should('be.disabled');
106
+ cy.getCy('titan-chat-input').should('be.visible').should('not.be.disabled');
107
+
108
+ cy.getCy('titan-chat-input').type('Hello');
109
+ cy.getCy('titan-chat-send').click();
110
+
111
+ cy.getCy('chat-message-user')
112
+ .should('be.visible')
113
+ .should('have.length', 1)
114
+ .should('contain.text', 'Hello');
115
+ cy.getCy('chat-message-typing').should('be.visible');
116
+ cy.getCy('chat-message-agent').should('have.length', 1);
117
+
118
+ cy.tick(1000);
119
+
120
+ cy.getCy('chat-message-typing').should('not.exist');
121
+ cy.getCy('chat-message-agent').should('have.length', 2);
122
+ });
123
+ });
124
+
125
+ it('should render chat error message', () => {
126
+ render().then(() => {
127
+ chatUiStore.setTimer({ secondsTotal: 100, secondsLeft: 10 });
128
+ chatUiStore.setError('Custom error', 'error message', true);
129
+
130
+ cy.getCy('titan-chat-timer').should('not.exist');
131
+ cy.getCy('titan-chat-error').should('be.visible');
132
+ });
133
+ });
134
+
135
+ it.only('should handle send message error and retry', () => {
136
+ render().then(() => {
137
+ ask('[Error]Custom error message');
138
+ cy.tick(1000);
139
+
140
+ // Check error message
141
+ cy.getCy('titan-chat-message-user-error')
142
+ .should('be.visible')
143
+ .should('contain.text', 'Message not delivered. Retry');
144
+ cy.getCy('titan-chat-error')
145
+ .should('be.visible')
146
+ .should(
147
+ 'contain.text',
148
+ ['Failed to send message', 'Custom error message'].join('')
149
+ );
150
+
151
+ // Retry message
152
+ cy.getCy('titan-chat-message-user-retry').should('be.visible').click();
153
+ cy.tick(1000);
154
+ });
155
+ });
156
+ });
@@ -0,0 +1,23 @@
1
+ import { BodyText, Spinner, Stack } from '@servicetitan/design-system';
2
+ import { FC } from 'react';
3
+
4
+ interface IChatConnectingProps {
5
+ className?: string;
6
+ }
7
+
8
+ export const ChatConnecting: FC<IChatConnectingProps> = ({ className }) => {
9
+ return (
10
+ <Stack
11
+ direction="column"
12
+ spacing="2"
13
+ alignItems="center"
14
+ className={className}
15
+ data-cy="titan-chat-connecting"
16
+ >
17
+ <Stack direction="row" spacing="2" alignItems="center">
18
+ <Spinner size="tiny" />
19
+ <BodyText className="c-neutral-100">Starting...</BodyText>
20
+ </Stack>
21
+ </Stack>
22
+ );
23
+ };
@@ -0,0 +1,6 @@
1
+ @import '@servicetitan/tokens/dist/tokens.less';
2
+
3
+ .banner {
4
+ border: @spacing-0 !important;
5
+ margin: @spacing-0 @spacing-3;
6
+ }
@@ -0,0 +1,3 @@
1
+ export const __esModule: true;
2
+ export const banner: string;
3
+
@@ -0,0 +1,39 @@
1
+ import { Banner, BodyText, Button } from '@servicetitan/design-system';
2
+ import { useDependencies } from '@servicetitan/react-ioc';
3
+ import { observer } from 'mobx-react';
4
+ import { FC, useCallback } from 'react';
5
+ import { CHAT_UI_STORE_TOKEN } from '../../stores';
6
+ import * as Styles from './chat-error.module.less';
7
+
8
+ export const ChatError: FC = observer(() => {
9
+ const [chatUiStore] = useDependencies(CHAT_UI_STORE_TOKEN);
10
+
11
+ const handleReconnect = useCallback(async () => {
12
+ await chatUiStore.recover();
13
+ }, [chatUiStore]);
14
+
15
+ if (!chatUiStore.error) {
16
+ return null;
17
+ }
18
+ return (
19
+ <Banner
20
+ status="critical"
21
+ title={chatUiStore.error.title}
22
+ icon
23
+ className={Styles.banner}
24
+ data-cy="titan-chat-error"
25
+ >
26
+ <BodyText el="div">{chatUiStore.error.message}</BodyText>
27
+ {chatUiStore.error.isRecoverable && (
28
+ <Button
29
+ className="m-t-2 bg-white-i"
30
+ small
31
+ onClick={handleReconnect}
32
+ data-cy="titan-chat-error-recover"
33
+ >
34
+ Reconnect
35
+ </Button>
36
+ )}
37
+ </Banner>
38
+ );
39
+ });
@@ -0,0 +1,68 @@
1
+ import { Eyebrow, FilePicker, Stack } from '@servicetitan/design-system';
2
+ import { FileDescriptor } from '@servicetitan/form';
3
+ import { useDependencies } from '@servicetitan/react-ioc';
4
+ import { observer } from 'mobx-react';
5
+ import { FC, useCallback, useEffect, useState } from 'react';
6
+ import { CHAT_UI_STORE_TOKEN } from '../../stores';
7
+
8
+ export const ChatInputFile: FC<{ className?: string }> = observer(({ className }) => {
9
+ const [chatUiStore] = useDependencies(CHAT_UI_STORE_TOKEN);
10
+ const [fileDescriptor, setFileDescriptor] = useState<FileDescriptor | undefined>(undefined);
11
+
12
+ const handleSelected = useCallback(
13
+ (newAttachments: FileList) => {
14
+ const fileDescriptor: FileDescriptor = {
15
+ file: newAttachments[0],
16
+ displayName: newAttachments[0].name,
17
+ };
18
+ setFileDescriptor(fileDescriptor);
19
+ chatUiStore.setFile(fileDescriptor);
20
+ },
21
+ [chatUiStore]
22
+ );
23
+
24
+ const handleReplace = useCallback(
25
+ ({ newFile }: { file: FileDescriptor; newFile: File }) => {
26
+ const fileDescriptor: FileDescriptor = {
27
+ file: newFile,
28
+ displayName: newFile.name,
29
+ };
30
+ setFileDescriptor(fileDescriptor);
31
+ chatUiStore.setFile(fileDescriptor);
32
+ },
33
+ [chatUiStore]
34
+ );
35
+
36
+ const handleDelete = useCallback(() => {
37
+ setFileDescriptor(undefined);
38
+ chatUiStore.setFile(undefined);
39
+ }, [chatUiStore]);
40
+
41
+ useEffect(() => {
42
+ if (!chatUiStore.file) {
43
+ setFileDescriptor(undefined);
44
+ }
45
+ }, [chatUiStore.file]);
46
+
47
+ if (!chatUiStore.isFilePickerEnabled) {
48
+ return null;
49
+ }
50
+ return (
51
+ <Stack className={className} spacing="3" direction="column">
52
+ <Eyebrow>Upload file</Eyebrow>
53
+ <FilePicker
54
+ name="attachments"
55
+ buttonProps={{
56
+ color: 'primary',
57
+ fill: 'outline',
58
+ }}
59
+ typesNote="e.g. Screenshot of issue"
60
+ value={fileDescriptor}
61
+ onSelected={handleSelected}
62
+ onDelete={handleDelete}
63
+ onReplace={handleReplace}
64
+ data-cy="titan-chat-upload-file"
65
+ />
66
+ </Stack>
67
+ );
68
+ });
@@ -0,0 +1,11 @@
1
+ @import '@servicetitan/tokens/dist/tokens.less';
2
+
3
+ .form-textarea {
4
+ margin-bottom: @spacing-0 !important;
5
+
6
+ textarea {
7
+ resize: none !important;
8
+ min-height: 40px;
9
+ line-height: 24px;
10
+ }
11
+ }
@@ -0,0 +1,3 @@
1
+ export const __esModule: true;
2
+ export const formTextarea: string;
3
+