@servicetitan/titan-chat-ui 1.0.1 → 1.1.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 (29) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/components/chat/__tests-cy__/chat.test.js +11 -6
  3. package/dist/components/chat/__tests-cy__/chat.test.js.map +1 -1
  4. package/dist/components/chat/chat-error.d.ts.map +1 -1
  5. package/dist/components/chat/chat-error.js +5 -3
  6. package/dist/components/chat/chat-error.js.map +1 -1
  7. package/dist/models/support-chat.d.ts +13 -3
  8. package/dist/models/support-chat.d.ts.map +1 -1
  9. package/dist/models/support-chat.js +29 -0
  10. package/dist/models/support-chat.js.map +1 -1
  11. package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts +3 -2
  12. package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts.map +1 -1
  13. package/dist/stores/__mocks-cy__/chat-ui.store.mock.js +6 -0
  14. package/dist/stores/__mocks-cy__/chat-ui.store.mock.js.map +1 -1
  15. package/dist/stores/chat-ui-backend-echo.store.d.ts.map +1 -1
  16. package/dist/stores/chat-ui-backend-echo.store.js +6 -2
  17. package/dist/stores/chat-ui-backend-echo.store.js.map +1 -1
  18. package/dist/stores/chat-ui.store.d.ts +7 -5
  19. package/dist/stores/chat-ui.store.d.ts.map +1 -1
  20. package/dist/stores/chat-ui.store.js +17 -11
  21. package/dist/stores/chat-ui.store.js.map +1 -1
  22. package/package.json +2 -2
  23. package/src/components/chat/__tests-cy__/chat.test.tsx +11 -9
  24. package/src/components/chat/chat-error.tsx +8 -6
  25. package/src/models/support-chat.ts +24 -3
  26. package/src/stores/__mocks-cy__/chat-ui.store.mock.ts +4 -2
  27. package/src/stores/chat-ui-backend-echo.store.ts +6 -2
  28. package/src/stores/chat-ui.store.ts +15 -11
  29. package/tsconfig.tsbuildinfo +1 -1
@@ -1,37 +1,39 @@
1
- import { Banner, BodyText, Button } from '@servicetitan/design-system';
1
+ import { Banner, Button } from '@servicetitan/design-system';
2
2
  import { useDependencies } from '@servicetitan/react-ioc';
3
3
  import { observer } from 'mobx-react';
4
4
  import { FC, useCallback } from 'react';
5
5
  import { CHAT_UI_STORE_TOKEN } from '../../stores';
6
+ import { MultilineText } from '../common/multiline-text';
6
7
  import * as Styles from './chat-error.module.less';
7
8
 
8
9
  export const ChatError: FC = observer(() => {
9
10
  const [chatUiStore] = useDependencies(CHAT_UI_STORE_TOKEN);
11
+ const { error } = chatUiStore;
10
12
 
11
13
  const handleReconnect = useCallback(async () => {
12
14
  await chatUiStore.recover();
13
15
  }, [chatUiStore]);
14
16
 
15
- if (!chatUiStore.error) {
17
+ if (!error) {
16
18
  return null;
17
19
  }
18
20
  return (
19
21
  <Banner
20
22
  status="critical"
21
- title={chatUiStore.error.title}
23
+ title={error.title}
22
24
  icon
23
25
  className={Styles.banner}
24
26
  data-cy="titan-chat-error"
25
27
  >
26
- <BodyText el="div">{chatUiStore.error.message}</BodyText>
27
- {chatUiStore.error.isRecoverable && (
28
+ <MultilineText text={error.message} />
29
+ {error.recoverStrategy && (
28
30
  <Button
29
31
  className="m-t-2 bg-white-i"
30
32
  small
31
33
  onClick={handleReconnect}
32
34
  data-cy="titan-chat-error-recover"
33
35
  >
34
- Reconnect
36
+ {error.recoverStrategy.recoverButtonTitle}
35
37
  </Button>
36
38
  )}
37
39
  </Banner>
@@ -69,10 +69,31 @@ export interface ChatMessageModelFile extends ChatMessageModelBase {
69
69
  fileName: string;
70
70
  }
71
71
 
72
- export interface ChatUiStateError {
72
+ type ChatErrorRecoverStrategy =
73
+ | {
74
+ recoverButtonTitle: string;
75
+ }
76
+ | false;
77
+
78
+ export interface ChatErrorOptions<T = any> {
79
+ title?: string;
80
+ recoverStrategy?: ChatErrorRecoverStrategy;
81
+ data?: T;
82
+ }
83
+
84
+ export class ChatError<T = any> extends Error {
73
85
  title: string;
74
- message: string;
75
- isRecoverable?: boolean;
86
+ recoverStrategy: ChatErrorRecoverStrategy;
87
+ data?: T;
88
+
89
+ constructor(message: string, options?: ChatErrorOptions<T>) {
90
+ super(message);
91
+ this.name = 'ChatError';
92
+ this.title = options?.title ?? 'Chat Error';
93
+ this.recoverStrategy = options?.recoverStrategy ?? false;
94
+ this.data = options?.data;
95
+ Object.setPrototypeOf(this, ChatError.prototype);
96
+ }
76
97
  }
77
98
 
78
99
  export enum ChatRunState {
@@ -2,6 +2,8 @@ import { FileDescriptor } from '@servicetitan/form';
2
2
  import {
3
3
  ChatConfiguration,
4
4
  ChatCustomizations,
5
+ ChatError,
6
+ ChatErrorOptions,
5
7
  ChatMessageModelBase,
6
8
  ChatMessageModelText,
7
9
  ChatMessageModelWelcome,
@@ -83,8 +85,8 @@ export class ChatUiStoreMock implements IChatUiStore {
83
85
  on: <T>(event: string, listener: ChatUiEventListener<T>) => void = cy.stub();
84
86
  resetError: (runState: ChatRunState) => void = cy.stub();
85
87
  setAgentTyping: (typing: boolean) => void = cy.stub();
86
- setError: (errorTitle: string, errorMessage: string, isRecoverableError?: boolean) => void =
87
- cy.stub();
88
+ setChatError: (chatError: ChatError) => void = cy.stub();
89
+ setError: <T = any>(message: string, options?: ChatErrorOptions<T>) => void = cy.stub();
88
90
  setFilePickerEnabled: (isEnabled: boolean) => void = cy.stub();
89
91
  setMessageState: (message: ChatMessageModelBase, state: ChatMessageState, data?: any) => void =
90
92
  cy.stub();
@@ -57,7 +57,9 @@ export class ChatUiBackendEchoStore implements IChatUiBackendStore {
57
57
  resolve();
58
58
  } catch (error: any) {
59
59
  this.chatUiStore.setMessageState(message, ChatMessageState.Failed);
60
- this.chatUiStore.setError('Failed to send message', error?.message ?? error, false);
60
+ this.chatUiStore.setError(error?.message ?? error, {
61
+ title: 'Custom Error Title',
62
+ });
61
63
  } finally {
62
64
  this.chatUiStore.setAgentTyping(false);
63
65
  }
@@ -77,7 +79,9 @@ export class ChatUiBackendEchoStore implements IChatUiBackendStore {
77
79
  resolve();
78
80
  } catch (error: any) {
79
81
  this.chatUiStore.setMessageState(message, ChatMessageState.Failed);
80
- this.chatUiStore.setError('Custom error', error?.message ?? error, false);
82
+ this.chatUiStore.setError(error?.message ?? error, {
83
+ title: 'Custom Error Title',
84
+ });
81
85
  }
82
86
  };
83
87
 
@@ -7,6 +7,8 @@ import {
7
7
  ChatConfiguration,
8
8
  ChatCustomizations,
9
9
  ChatEndReason,
10
+ ChatError,
11
+ ChatErrorOptions,
10
12
  ChatMessageModelBase,
11
13
  ChatMessageModelFile,
12
14
  ChatMessageModelText,
@@ -18,7 +20,6 @@ import {
18
20
  ChatParticipantModel,
19
21
  ChatRunState,
20
22
  ChatTimer,
21
- ChatUiStateError,
22
23
  } from '../models';
23
24
 
24
25
  export const symbolAgent = Symbol('SupportChatAgent');
@@ -59,7 +60,7 @@ export interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations>
59
60
  isAgentTyping: boolean;
60
61
  isFilePickerEnabled: boolean;
61
62
  file?: FileDescriptor;
62
- error?: ChatUiStateError;
63
+ error?: ChatError;
63
64
 
64
65
  get agent(): ChatParticipantModel;
65
66
  get user(): ChatParticipantModel;
@@ -77,7 +78,8 @@ export interface IChatUiStore<T extends ChatCustomizations = ChatCustomizations>
77
78
  setMessages(messages: ChatMessageModelBase[]): void;
78
79
  setAgentName(name: string): void;
79
80
  setAgentIcon(icon: ChatParticipantIcon): void;
80
- setError(errorTitle: string, errorMessage: string, isRecoverableError?: boolean): void;
81
+ setChatError(chatError: ChatError): void;
82
+ setError<T = any>(message: string, options?: ChatErrorOptions<T>): void;
81
83
  setStatus(status: ChatRunState): void;
82
84
  resetError(runState: ChatRunState): void;
83
85
 
@@ -105,7 +107,7 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
105
107
 
106
108
  file?: FileDescriptor;
107
109
 
108
- @observable error?: ChatUiStateError;
110
+ @observable.ref error?: ChatError;
109
111
 
110
112
  @observable endReason?: ChatEndReason;
111
113
 
@@ -220,16 +222,18 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
220
222
  }
221
223
 
222
224
  @action
223
- setError(errorTitle: string, errorMessage: string, isRecoverableError = false) {
224
- this.error = {
225
- message: errorMessage,
226
- isRecoverable: isRecoverableError,
227
- title: errorTitle,
228
- };
225
+ setChatError(chatError: ChatError) {
226
+ this.error = chatError;
229
227
  this.setStatus(ChatRunState.Error);
230
228
  this.triggerScroll();
231
229
  }
232
230
 
231
+ @action
232
+ setError<T = any>(message: string, options?: ChatErrorOptions<T>) {
233
+ this.error = new ChatError(message, options);
234
+ this.setChatError(this.error);
235
+ }
236
+
233
237
  @action
234
238
  setStatus(status: ChatRunState) {
235
239
  this.status = status;
@@ -294,7 +298,7 @@ export class ChatUiStore<T extends ChatCustomizations> implements IChatUiStore<T
294
298
  }
295
299
 
296
300
  async recover() {
297
- await this.emitAsync(ChatUiEvent.eventRecover);
301
+ await this.emitAsync(ChatUiEvent.eventRecover, this.error);
298
302
  }
299
303
 
300
304
  async destroy() {