@servicetitan/titan-chat-ui 1.1.2 → 2.0.0

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 (90) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/components/chat/__tests-cy__/chat-messages.test.js +69 -1
  3. package/dist/components/chat/__tests-cy__/chat-messages.test.js.map +1 -1
  4. package/dist/components/chat/chat-input.js +2 -2
  5. package/dist/components/chat/chat-input.js.map +1 -1
  6. package/dist/components/chat/chat-log.d.ts +8 -0
  7. package/dist/components/chat/chat-log.d.ts.map +1 -0
  8. package/dist/components/chat/chat-log.js +15 -0
  9. package/dist/components/chat/chat-log.js.map +1 -0
  10. package/dist/components/chat/chat-message-template-agent.d.ts.map +1 -1
  11. package/dist/components/chat/chat-message-template-agent.js +2 -2
  12. package/dist/components/chat/chat-message-template-agent.js.map +1 -1
  13. package/dist/components/chat/chat-message-template-user.js +2 -2
  14. package/dist/components/chat/chat-message-template-user.js.map +1 -1
  15. package/dist/components/chat/chat-message.d.ts +1 -5
  16. package/dist/components/chat/chat-message.d.ts.map +1 -1
  17. package/dist/components/chat/chat-message.js +4 -4
  18. package/dist/components/chat/chat-message.js.map +1 -1
  19. package/dist/components/chat/chat-messages.d.ts +3 -0
  20. package/dist/components/chat/chat-messages.d.ts.map +1 -1
  21. package/dist/components/chat/chat-messages.js +35 -7
  22. package/dist/components/chat/chat-messages.js.map +1 -1
  23. package/dist/components/chat/chat.d.ts.map +1 -1
  24. package/dist/components/chat/chat.js +3 -1
  25. package/dist/components/chat/chat.js.map +1 -1
  26. package/dist/components/messages/__tests-cy__/message-agent.test.js +1 -1
  27. package/dist/components/messages/__tests-cy__/message-agent.test.js.map +1 -1
  28. package/dist/components/messages/message-agent.d.ts +1 -0
  29. package/dist/components/messages/message-agent.d.ts.map +1 -1
  30. package/dist/components/messages/message-agent.js +2 -4
  31. package/dist/components/messages/message-agent.js.map +1 -1
  32. package/dist/components/messages/message-agent.module.less +29 -37
  33. package/dist/components/messages/message-footer.d.ts +1 -1
  34. package/dist/components/messages/message-footer.d.ts.map +1 -1
  35. package/dist/components/messages/message-footer.js +1 -1
  36. package/dist/components/messages/message-footer.js.map +1 -1
  37. package/dist/components/messages/message-user.js +2 -2
  38. package/dist/components/messages/message-user.js.map +1 -1
  39. package/dist/components/messages/message-user.module.less +3 -6
  40. package/dist/index.d.ts +3 -0
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +3 -0
  43. package/dist/index.js.map +1 -1
  44. package/dist/models/chat-customizations.d.ts +14 -6
  45. package/dist/models/chat-customizations.d.ts.map +1 -1
  46. package/dist/models/support-chat.d.ts +4 -4
  47. package/dist/models/support-chat.d.ts.map +1 -1
  48. package/dist/models/support-chat.js +18 -0
  49. package/dist/models/support-chat.js.map +1 -1
  50. package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts +6 -1
  51. package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts.map +1 -1
  52. package/dist/stores/__mocks-cy__/chat-ui.store.mock.js +30 -0
  53. package/dist/stores/__mocks-cy__/chat-ui.store.mock.js.map +1 -1
  54. package/dist/stores/__tests__/chat-input.store.test.d.ts +2 -0
  55. package/dist/stores/__tests__/chat-input.store.test.d.ts.map +1 -0
  56. package/dist/stores/__tests__/chat-input.store.test.js +32 -0
  57. package/dist/stores/__tests__/chat-input.store.test.js.map +1 -0
  58. package/dist/stores/chat-ui.store.d.ts +19 -10
  59. package/dist/stores/chat-ui.store.d.ts.map +1 -1
  60. package/dist/stores/chat-ui.store.js +47 -48
  61. package/dist/stores/chat-ui.store.js.map +1 -1
  62. package/dist/utils/test-utils.d.ts +5 -0
  63. package/dist/utils/test-utils.d.ts.map +1 -0
  64. package/dist/utils/test-utils.js +17 -0
  65. package/dist/utils/test-utils.js.map +1 -0
  66. package/package.json +2 -2
  67. package/src/components/chat/__tests-cy__/chat-messages.test.tsx +78 -1
  68. package/src/components/chat/chat-input.tsx +4 -4
  69. package/src/components/chat/chat-log.tsx +29 -0
  70. package/src/components/chat/chat-message-template-agent.tsx +7 -3
  71. package/src/components/chat/chat-message-template-user.tsx +3 -3
  72. package/src/components/chat/chat-message.tsx +58 -52
  73. package/src/components/chat/chat-messages.tsx +55 -11
  74. package/src/components/chat/chat.tsx +14 -8
  75. package/src/components/messages/__tests-cy__/message-agent.test.tsx +1 -1
  76. package/src/components/messages/message-agent.module.less +29 -37
  77. package/src/components/messages/message-agent.module.less.d.ts +0 -1
  78. package/src/components/messages/message-agent.tsx +4 -4
  79. package/src/components/messages/message-footer.tsx +4 -3
  80. package/src/components/messages/message-user.module.less +3 -6
  81. package/src/components/messages/message-user.tsx +5 -5
  82. package/src/index.ts +3 -0
  83. package/src/models/chat-customizations.ts +17 -6
  84. package/src/models/support-chat.ts +22 -10
  85. package/src/stores/__mocks-cy__/chat-ui.store.mock.ts +6 -0
  86. package/src/stores/__tests__/chat-input.store.test.ts +39 -0
  87. package/src/stores/chat-ui.store.ts +54 -55
  88. package/src/utils/test-utils.ts +22 -0
  89. package/tsconfig.json +1 -2
  90. package/tsconfig.tsbuildinfo +1 -1
@@ -13,7 +13,6 @@ import {
13
13
  ChatMessageModelFile,
14
14
  ChatMessageModelText,
15
15
  ChatMessageModelTimeout,
16
- ChatMessageModelType,
17
16
  ChatMessageModelWelcome,
18
17
  ChatMessageState,
19
18
  ChatParticipantIcon,
@@ -29,12 +28,15 @@ export enum ChatUiEvent {
29
28
  eventRun = 'eventRun',
30
29
  eventDestroy = 'eventDestroy',
31
30
  eventRestart = 'eventRestart',
31
+ eventCancel = 'eventCancel',
32
+ eventEndChat = 'eventEndChat',
32
33
  eventRecover = 'eventRecover',
33
34
  eventChasitorTyping = 'eventChasitorTyping',
34
35
  eventTimerRestart = 'eventTimerRestart',
35
36
  eventMessageSend = 'eventMessageSend',
36
- eventMessageSendFile = 'eventMessageSendFile',
37
37
  eventMessageSendRetry = 'eventMessageSendRetry',
38
+ eventMessageSendFile = 'eventMessageSendFile',
39
+ eventMessageSendFileRetry = 'eventMessageSendFileRetry',
38
40
  }
39
41
 
40
42
  export type ChatUiEventListener<T = void> = (
@@ -82,6 +84,8 @@ export interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations>
82
84
  setError<T = any>(message: string, options?: ChatErrorOptions<T>): void;
83
85
  setStatus(status: ChatRunState): void;
84
86
  resetError(runState: ChatRunState): void;
87
+ reset(resetStatus?: boolean): void;
88
+ resetFile(): void;
85
89
 
86
90
  triggerScroll(): void;
87
91
  configure(configuration?: ChatConfiguration): void;
@@ -90,6 +94,9 @@ export interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations>
90
94
  destroy(): Promise<void>;
91
95
  chasitorTyping(isTyping: boolean): Promise<void>;
92
96
  restartTimers(): Promise<void>;
97
+ restart(): Promise<void>;
98
+ cancelChat(): Promise<void>;
99
+ endChat(endReason?: ChatEndReason): Promise<void>;
93
100
  sendMessageText(messageText: string): Promise<void>;
94
101
  sendMessageRetry(message: ChatMessageModelBase): Promise<void>;
95
102
  addMessage(isAgent: boolean, message: string, data?: any): void;
@@ -306,24 +313,21 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
306
313
  await this.emitAsync(ChatUiEvent.eventDestroy);
307
314
  }
308
315
 
309
- restart() {
316
+ async restart() {
310
317
  this.reset();
311
- this.eventEmitter.emit('restart');
318
+ await this.emitAsync(ChatUiEvent.eventRestart);
312
319
  }
313
320
 
314
- cancelChat() {
315
- this.eventEmitter.emit('cancelChat');
321
+ async cancelChat() {
322
+ await this.emitAsync(ChatUiEvent.eventCancel);
316
323
  }
317
324
 
318
- endChat() {
319
- this.eventEmitter.emit('endChat');
325
+ async endChat(endReason?: ChatEndReason) {
326
+ await this.emitAsync(ChatUiEvent.eventEndChat, endReason);
320
327
  }
321
328
 
322
329
  async chasitorTyping(isTyping: boolean) {
323
- await this.emitAsync(
324
- ChatUiEvent.eventChasitorTyping,
325
- isTyping ? 'chasitorTyping' : 'chasitorNotTyping'
326
- );
330
+ await this.emitAsync(ChatUiEvent.eventChasitorTyping, isTyping);
327
331
  }
328
332
 
329
333
  @action
@@ -358,10 +362,10 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
358
362
  }
359
363
 
360
364
  @action
361
- sendMessageFileRetry(messageModel: ChatMessageModelFile) {
365
+ async sendMessageFileRetry(messageModel: ChatMessageModelFile) {
362
366
  this.resetError(ChatRunState.Started);
363
367
  this.setMessageState(messageModel, ChatMessageState.Delivering);
364
- this.eventEmitter.emit('sendMessageFileRetry', messageModel);
368
+ await this.emitAsync(ChatUiEvent.eventMessageSendFileRetry, messageModel);
365
369
  }
366
370
 
367
371
  getParticipant(participantKey: symbol): ChatParticipantModel {
@@ -431,6 +435,26 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
431
435
  }
432
436
  }
433
437
 
438
+ @action
439
+ resetFile() {
440
+ this.currentFileMessage = undefined;
441
+ this.file = undefined;
442
+ this.isFilePickerEnabled = false;
443
+ this.triggerScroll();
444
+ }
445
+
446
+ @action
447
+ reset(resetStatus = true) {
448
+ this.setMessages([]);
449
+ if (resetStatus) {
450
+ this.status = ChatRunState.Offline;
451
+ }
452
+ this.error = undefined;
453
+ this.isAgentTyping = false;
454
+ this.endReason = undefined;
455
+ this.resetFile();
456
+ }
457
+
434
458
  getLastFailedMessages() {
435
459
  const result: ChatMessageModelText[] = [];
436
460
  for (let i = this.messages.length - 1; i >= 0; i--) {
@@ -453,26 +477,6 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
453
477
  }, 0);
454
478
  }
455
479
 
456
- @action
457
- protected reset(resetStatus = true) {
458
- this.setMessages([]);
459
- if (resetStatus) {
460
- this.status = ChatRunState.Offline;
461
- }
462
- this.error = undefined;
463
- this.isAgentTyping = false;
464
- this.endReason = undefined;
465
- this.resetFile();
466
- }
467
-
468
- @action
469
- protected resetFile() {
470
- this.currentFileMessage = undefined;
471
- this.file = undefined;
472
- this.isFilePickerEnabled = false;
473
- this.triggerScroll();
474
- }
475
-
476
480
  protected async emitAsync<T>(event: string, ...args: unknown[]) {
477
481
  if (!this.eventEmitter.listenerCount(event)) {
478
482
  return Promise.resolve();
@@ -482,23 +486,14 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
482
486
  });
483
487
  }
484
488
 
485
- private async sendMessageTextInternal(message: string) {
486
- if (message.trim() === '') {
487
- return;
488
- }
489
- const messageModel = this.addMessage(false, message);
490
- await this.emitAsync(ChatUiEvent.eventMessageSend, messageModel);
491
- }
492
-
493
- private addMessageInternal<T extends ChatMessageModelBase>(
489
+ protected addMessageInternal<T extends ChatMessageModelBase>(
494
490
  message: Omit<T, 'id' | 'timestamp'>
495
491
  ): T {
496
492
  if (message.type === 'timeout') {
497
493
  this.removeMessageByType('timeout'); // Remove previous timeout messages
498
494
  } else {
499
- this.restartTimers();
495
+ this.restartTimers().then(() => {});
500
496
  }
501
- this.removeAskSupportButtons();
502
497
  const newMessage = this.createMessage<T>(message);
503
498
  this.setMessages([...this.messages, newMessage]);
504
499
  if (message.participant.isAgent) {
@@ -507,6 +502,20 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
507
502
  return newMessage;
508
503
  }
509
504
 
505
+ protected removeMessageByType(type: string) {
506
+ if (this.messages.some(m => m.type === type)) {
507
+ this.setMessages(this.messages.filter(m => m.type !== type));
508
+ }
509
+ }
510
+
511
+ private async sendMessageTextInternal(message: string) {
512
+ if (message.trim() === '') {
513
+ return;
514
+ }
515
+ const messageModel = this.addMessage(false, message);
516
+ await this.emitAsync(ChatUiEvent.eventMessageSend, messageModel);
517
+ }
518
+
510
519
  private createMessage<T extends ChatMessageModelBase>(rest: Omit<T, 'id' | 'timestamp'>) {
511
520
  return {
512
521
  id: nanoid(),
@@ -528,14 +537,4 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
528
537
  this.incomingMessageSoundPromise = undefined;
529
538
  }
530
539
  }
531
-
532
- private removeMessageByType(type: ChatMessageModelType) {
533
- if (this.messages.some(m => m.type === type)) {
534
- this.setMessages(this.messages.filter(m => m.type !== type));
535
- }
536
- }
537
-
538
- private removeAskSupportButtons() {
539
- this.removeMessageByType('askSupportButtons');
540
- }
541
540
  }
@@ -0,0 +1,22 @@
1
+ import { Container } from '@servicetitan/react-ioc';
2
+
3
+ type Newable<T> = new (...args: never[]) => T;
4
+
5
+ export const initTestContainer = (
6
+ serviceIdentifier: Newable<unknown> | Newable<unknown>[],
7
+ initDependenciesFn: (container: Container) => void
8
+ ) => {
9
+ const rootContainer = new Container();
10
+ if (Array.isArray(serviceIdentifier)) {
11
+ serviceIdentifier.forEach(identifier => rootContainer.bind(identifier).toSelf());
12
+ } else {
13
+ rootContainer.bind(serviceIdentifier).toSelf();
14
+ }
15
+
16
+ return () => {
17
+ const container = new Container();
18
+ container.parent = rootContainer;
19
+ initDependenciesFn(container);
20
+ return container;
21
+ };
22
+ };
package/tsconfig.json CHANGED
@@ -9,7 +9,6 @@
9
9
  },
10
10
  "include": ["src/**/*"],
11
11
  "exclude": [
12
- "node_modules",
13
- "src/**/__tests__/**/*"
12
+ "node_modules"
14
13
  ]
15
14
  }