@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.
- package/CHANGELOG.md +11 -0
- package/dist/assets/floating-chat-avatar.svg +16 -0
- package/dist/components/chat/__tests-cy__/chat-messages.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat-messages.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat-messages.test.js +28 -0
- package/dist/components/chat/__tests-cy__/chat-messages.test.js.map +1 -0
- package/dist/components/chat/__tests-cy__/chat.test.d.ts +2 -0
- package/dist/components/chat/__tests-cy__/chat.test.d.ts.map +1 -0
- package/dist/components/chat/__tests-cy__/chat.test.js +122 -0
- package/dist/components/chat/__tests-cy__/chat.test.js.map +1 -0
- package/dist/components/chat/chat-connecting.d.ts +7 -0
- package/dist/components/chat/chat-connecting.d.ts.map +1 -0
- package/dist/components/chat/chat-connecting.js +6 -0
- package/dist/components/chat/chat-connecting.js.map +1 -0
- package/dist/components/chat/chat-error.d.ts +3 -0
- package/dist/components/chat/chat-error.d.ts.map +1 -0
- package/dist/components/chat/chat-error.js +18 -0
- package/dist/components/chat/chat-error.js.map +1 -0
- package/dist/components/chat/chat-error.module.less +6 -0
- package/dist/components/chat/chat-input-file.d.ts +5 -0
- package/dist/components/chat/chat-input-file.d.ts.map +1 -0
- package/dist/components/chat/chat-input-file.js +43 -0
- package/dist/components/chat/chat-input-file.js.map +1 -0
- package/dist/components/chat/chat-input.d.ts +5 -0
- package/dist/components/chat/chat-input.d.ts.map +1 -0
- package/dist/components/chat/chat-input.js +94 -0
- package/dist/components/chat/chat-input.js.map +1 -0
- package/dist/components/chat/chat-input.module.less +11 -0
- package/dist/components/chat/chat-message-template-agent.d.ts +4 -0
- package/dist/components/chat/chat-message-template-agent.d.ts.map +1 -0
- package/dist/components/chat/chat-message-template-agent.js +14 -0
- package/dist/components/chat/chat-message-template-agent.js.map +1 -0
- package/dist/components/chat/chat-message-template-user.d.ts +4 -0
- package/dist/components/chat/chat-message-template-user.d.ts.map +1 -0
- package/dist/components/chat/chat-message-template-user.js +16 -0
- package/dist/components/chat/chat-message-template-user.js.map +1 -0
- package/dist/components/chat/chat-message-typing.d.ts +3 -0
- package/dist/components/chat/chat-message-typing.d.ts.map +1 -0
- package/dist/components/chat/chat-message-typing.js +15 -0
- package/dist/components/chat/chat-message-typing.js.map +1 -0
- package/dist/components/chat/chat-message.d.ts +12 -0
- package/dist/components/chat/chat-message.d.ts.map +1 -0
- package/dist/components/chat/chat-message.js +60 -0
- package/dist/components/chat/chat-message.js.map +1 -0
- package/dist/components/chat/chat-messages.d.ts +7 -0
- package/dist/components/chat/chat-messages.d.ts.map +1 -0
- package/dist/components/chat/chat-messages.js +12 -0
- package/dist/components/chat/chat-messages.js.map +1 -0
- package/dist/components/chat/chat-notifications.d.ts +5 -0
- package/dist/components/chat/chat-notifications.d.ts.map +1 -0
- package/dist/components/chat/chat-notifications.js +12 -0
- package/dist/components/chat/chat-notifications.js.map +1 -0
- package/dist/components/chat/chat-timer.d.ts +3 -0
- package/dist/components/chat/chat-timer.d.ts.map +1 -0
- package/dist/components/chat/chat-timer.js +18 -0
- package/dist/components/chat/chat-timer.js.map +1 -0
- package/dist/components/chat/chat-timer.module.less +5 -0
- package/dist/components/chat/chat.d.ts +8 -0
- package/dist/components/chat/chat.d.ts.map +1 -0
- package/dist/components/chat/chat.js +28 -0
- package/dist/components/chat/chat.js.map +1 -0
- package/dist/components/common/multiline-text.d.ts +8 -0
- package/dist/components/common/multiline-text.d.ts.map +1 -0
- package/dist/components/common/multiline-text.js +12 -0
- package/dist/components/common/multiline-text.js.map +1 -0
- package/dist/components/common/multiline-text.module.less +9 -0
- package/dist/components/message-content/message-content-file.d.ts +8 -0
- package/dist/components/message-content/message-content-file.d.ts.map +1 -0
- package/dist/components/message-content/message-content-file.js +11 -0
- package/dist/components/message-content/message-content-file.js.map +1 -0
- package/dist/components/message-content/message-content-text.d.ts +8 -0
- package/dist/components/message-content/message-content-text.d.ts.map +1 -0
- package/dist/components/message-content/message-content-text.js +7 -0
- package/dist/components/message-content/message-content-text.js.map +1 -0
- package/dist/components/messages/__tests-cy__/message-agent.test.d.ts +2 -0
- package/dist/components/messages/__tests-cy__/message-agent.test.d.ts.map +1 -0
- package/dist/components/messages/__tests-cy__/message-agent.test.js +89 -0
- package/dist/components/messages/__tests-cy__/message-agent.test.js.map +1 -0
- package/dist/components/messages/__tests-cy__/message-system.test.d.ts +2 -0
- package/dist/components/messages/__tests-cy__/message-system.test.d.ts.map +1 -0
- package/dist/components/messages/__tests-cy__/message-system.test.js +20 -0
- package/dist/components/messages/__tests-cy__/message-system.test.js.map +1 -0
- package/dist/components/messages/__tests-cy__/message-timeout.test.d.ts +2 -0
- package/dist/components/messages/__tests-cy__/message-timeout.test.d.ts.map +1 -0
- package/dist/components/messages/__tests-cy__/message-timeout.test.js +32 -0
- package/dist/components/messages/__tests-cy__/message-timeout.test.js.map +1 -0
- package/dist/components/messages/__tests-cy__/message-typing.test.d.ts +2 -0
- package/dist/components/messages/__tests-cy__/message-typing.test.d.ts.map +1 -0
- package/dist/components/messages/__tests-cy__/message-typing.test.js +49 -0
- package/dist/components/messages/__tests-cy__/message-typing.test.js.map +1 -0
- package/dist/components/messages/__tests-cy__/message-user.test.d.ts +2 -0
- package/dist/components/messages/__tests-cy__/message-user.test.d.ts.map +1 -0
- package/dist/components/messages/__tests-cy__/message-user.test.js +33 -0
- package/dist/components/messages/__tests-cy__/message-user.test.js.map +1 -0
- package/dist/components/messages/message-agent.d.ts +12 -0
- package/dist/components/messages/message-agent.d.ts.map +1 -0
- package/dist/components/messages/message-agent.js +18 -0
- package/dist/components/messages/message-agent.js.map +1 -0
- package/dist/components/messages/message-agent.module.less +59 -0
- package/dist/components/messages/message-avatar.d.ts +9 -0
- package/dist/components/messages/message-avatar.d.ts.map +1 -0
- package/dist/components/messages/message-avatar.js +14 -0
- package/dist/components/messages/message-avatar.js.map +1 -0
- package/dist/components/messages/message-avatar.module.less +26 -0
- package/dist/components/messages/message-footer.d.ts +7 -0
- package/dist/components/messages/message-footer.d.ts.map +1 -0
- package/dist/components/messages/message-footer.js +7 -0
- package/dist/components/messages/message-footer.js.map +1 -0
- package/dist/components/messages/message-system.d.ts +8 -0
- package/dist/components/messages/message-system.d.ts.map +1 -0
- package/dist/components/messages/message-system.js +12 -0
- package/dist/components/messages/message-system.js.map +1 -0
- package/dist/components/messages/message-system.module.less +26 -0
- package/dist/components/messages/message-timeout.d.ts +8 -0
- package/dist/components/messages/message-timeout.d.ts.map +1 -0
- package/dist/components/messages/message-timeout.js +16 -0
- package/dist/components/messages/message-timeout.js.map +1 -0
- package/dist/components/messages/message-typing.d.ts +8 -0
- package/dist/components/messages/message-typing.d.ts.map +1 -0
- package/dist/components/messages/message-typing.js +10 -0
- package/dist/components/messages/message-typing.js.map +1 -0
- package/dist/components/messages/message-typing.module.less +40 -0
- package/dist/components/messages/message-user.d.ts +9 -0
- package/dist/components/messages/message-user.d.ts.map +1 -0
- package/dist/components/messages/message-user.js +13 -0
- package/dist/components/messages/message-user.js.map +1 -0
- package/dist/components/messages/message-user.module.less +35 -0
- package/dist/components/messages/use-avatar-props.d.ts +4 -0
- package/dist/components/messages/use-avatar-props.d.ts.map +1 -0
- package/dist/components/messages/use-avatar-props.js +12 -0
- package/dist/components/messages/use-avatar-props.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/models/chat-customizations.d.ts +29 -0
- package/dist/models/chat-customizations.d.ts.map +1 -0
- package/dist/models/chat-customizations.js +2 -0
- package/dist/models/chat-customizations.js.map +1 -0
- package/dist/models/component.d.ts +4 -0
- package/dist/models/component.d.ts.map +1 -0
- package/dist/models/component.js +2 -0
- package/dist/models/component.js.map +1 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +3 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/support-chat.d.ts +66 -0
- package/dist/models/support-chat.d.ts.map +1 -0
- package/dist/models/support-chat.js +28 -0
- package/dist/models/support-chat.js.map +1 -0
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts +65 -0
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.d.ts.map +1 -0
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.js +268 -0
- package/dist/stores/__mocks-cy__/chat-ui.store.mock.js.map +1 -0
- package/dist/stores/chat-input.store.d.ts +10 -0
- package/dist/stores/chat-input.store.d.ts.map +1 -0
- package/dist/stores/chat-input.store.js +46 -0
- package/dist/stores/chat-input.store.js.map +1 -0
- package/dist/stores/chat-ui-backend-echo.store.d.ts +13 -0
- package/dist/stores/chat-ui-backend-echo.store.d.ts.map +1 -0
- package/dist/stores/chat-ui-backend-echo.store.js +111 -0
- package/dist/stores/chat-ui-backend-echo.store.js.map +1 -0
- package/dist/stores/chat-ui-backend.store.d.ts +6 -0
- package/dist/stores/chat-ui-backend.store.d.ts.map +1 -0
- package/dist/stores/chat-ui-backend.store.js +3 -0
- package/dist/stores/chat-ui-backend.store.js.map +1 -0
- package/dist/stores/chat-ui.store.d.ts +142 -0
- package/dist/stores/chat-ui.store.d.ts.map +1 -0
- package/dist/stores/chat-ui.store.js +679 -0
- package/dist/stores/chat-ui.store.js.map +1 -0
- package/dist/stores/index.d.ts +3 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +3 -0
- package/dist/stores/index.js.map +1 -0
- package/dist/utils/text-utils.d.ts +11 -0
- package/dist/utils/text-utils.d.ts.map +1 -0
- package/dist/utils/text-utils.js +82 -0
- package/dist/utils/text-utils.js.map +1 -0
- package/package.json +52 -0
- package/src/assets/floating-chat-avatar.svg +16 -0
- package/src/components/chat/__tests-cy__/chat-messages.test.tsx +36 -0
- package/src/components/chat/__tests-cy__/chat.test.tsx +156 -0
- package/src/components/chat/chat-connecting.tsx +23 -0
- package/src/components/chat/chat-error.module.less +6 -0
- package/src/components/chat/chat-error.module.less.d.ts +3 -0
- package/src/components/chat/chat-error.tsx +39 -0
- package/src/components/chat/chat-input-file.tsx +68 -0
- package/src/components/chat/chat-input.module.less +11 -0
- package/src/components/chat/chat-input.module.less.d.ts +3 -0
- package/src/components/chat/chat-input.tsx +143 -0
- package/src/components/chat/chat-message-template-agent.tsx +26 -0
- package/src/components/chat/chat-message-template-user.tsx +46 -0
- package/src/components/chat/chat-message-typing.tsx +19 -0
- package/src/components/chat/chat-message.tsx +78 -0
- package/src/components/chat/chat-messages.tsx +23 -0
- package/src/components/chat/chat-notifications.tsx +19 -0
- package/src/components/chat/chat-timer.module.less +5 -0
- package/src/components/chat/chat-timer.module.less.d.ts +3 -0
- package/src/components/chat/chat-timer.tsx +35 -0
- package/src/components/chat/chat.tsx +55 -0
- package/src/components/common/multiline-text.module.less +9 -0
- package/src/components/common/multiline-text.module.less.d.ts +3 -0
- package/src/components/common/multiline-text.tsx +30 -0
- package/src/components/message-content/message-content-file.tsx +27 -0
- package/src/components/message-content/message-content-text.tsx +12 -0
- package/src/components/messages/__tests-cy__/message-agent.test.tsx +155 -0
- package/src/components/messages/__tests-cy__/message-system.test.tsx +33 -0
- package/src/components/messages/__tests-cy__/message-timeout.test.tsx +38 -0
- package/src/components/messages/__tests-cy__/message-typing.test.tsx +58 -0
- package/src/components/messages/__tests-cy__/message-user.test.tsx +52 -0
- package/src/components/messages/message-agent.module.less +59 -0
- package/src/components/messages/message-agent.module.less.d.ts +9 -0
- package/src/components/messages/message-agent.tsx +62 -0
- package/src/components/messages/message-avatar.module.less +26 -0
- package/src/components/messages/message-avatar.module.less.d.ts +5 -0
- package/src/components/messages/message-avatar.tsx +33 -0
- package/src/components/messages/message-footer.tsx +17 -0
- package/src/components/messages/message-system.module.less +26 -0
- package/src/components/messages/message-system.module.less.d.ts +5 -0
- package/src/components/messages/message-system.tsx +35 -0
- package/src/components/messages/message-timeout.tsx +42 -0
- package/src/components/messages/message-typing.module.less +40 -0
- package/src/components/messages/message-typing.module.less.d.ts +5 -0
- package/src/components/messages/message-typing.tsx +25 -0
- package/src/components/messages/message-user.module.less +35 -0
- package/src/components/messages/message-user.module.less.d.ts +7 -0
- package/src/components/messages/message-user.tsx +49 -0
- package/src/components/messages/use-avatar-props.tsx +17 -0
- package/src/cypress.d.ts +10 -0
- package/src/index.ts +11 -0
- package/src/models/chat-customizations.ts +34 -0
- package/src/models/component.ts +3 -0
- package/src/models/index.ts +2 -0
- package/src/models/support-chat.ts +84 -0
- package/src/stores/__mocks-cy__/chat-ui.store.mock.ts +105 -0
- package/src/stores/chat-input.store.ts +25 -0
- package/src/stores/chat-ui-backend-echo.store.ts +94 -0
- package/src/stores/chat-ui-backend.store.ts +10 -0
- package/src/stores/chat-ui.store.ts +537 -0
- package/src/stores/index.ts +10 -0
- package/src/utils/text-utils.ts +93 -0
- package/tsconfig.json +15 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// eslint-disable-next-line spaced-comment
|
|
2
|
+
/// <reference types="../../../cypress" />
|
|
3
|
+
import { BodyText, Button, Stack } from '@servicetitan/design-system';
|
|
4
|
+
import { mount } from 'cypress/react';
|
|
5
|
+
import { ChatParticipantIcon } from '../../../models/support-chat';
|
|
6
|
+
import { MessageAgent } from '../message-agent';
|
|
7
|
+
import { MessageFooter } from '../message-footer';
|
|
8
|
+
|
|
9
|
+
describe('[MessageAgent]', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
cy.viewport('macbook-13');
|
|
12
|
+
cy.clock(new Date('2023-10-10T10:10:00Z').getTime());
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should be properly rendered', () => {
|
|
16
|
+
mount(
|
|
17
|
+
<MessageAgent
|
|
18
|
+
avatar={{
|
|
19
|
+
name: 'Test User Name',
|
|
20
|
+
icon: ChatParticipantIcon.Bot,
|
|
21
|
+
className: 'custom-class',
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
<BodyText data-cy="content">message agent content</BodyText>
|
|
25
|
+
</MessageAgent>
|
|
26
|
+
);
|
|
27
|
+
cy.getCy('chat-message-agent').should('be.visible').children().should('have.length', 2);
|
|
28
|
+
cy.getCy('chat-avatar-bot').should('be.visible').should('have.class', 'custom-class');
|
|
29
|
+
cy.getCy('chat-message-agent-content')
|
|
30
|
+
|
|
31
|
+
.should('contain.text', 'message agent content');
|
|
32
|
+
cy.getCy('content').should('contain.text', 'message agent content');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should be full width', () => {
|
|
36
|
+
mount(
|
|
37
|
+
<MessageAgent
|
|
38
|
+
fullWidth
|
|
39
|
+
avatar={{
|
|
40
|
+
name: 'Test User Name',
|
|
41
|
+
icon: ChatParticipantIcon.Bot,
|
|
42
|
+
}}
|
|
43
|
+
>
|
|
44
|
+
<BodyText>message agent content</BodyText>
|
|
45
|
+
</MessageAgent>
|
|
46
|
+
);
|
|
47
|
+
cy.getCy('chat-message-agent-center').should('have.class', 'w-100');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('should render with custom data-cy', () => {
|
|
51
|
+
mount(
|
|
52
|
+
<MessageAgent
|
|
53
|
+
data-cy="custom-data-cy"
|
|
54
|
+
avatar={{
|
|
55
|
+
name: 'Test User Name',
|
|
56
|
+
icon: ChatParticipantIcon.Bot,
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<BodyText>message agent content</BodyText>
|
|
60
|
+
</MessageAgent>
|
|
61
|
+
);
|
|
62
|
+
cy.getCy('custom-data-cy').should('be.visible');
|
|
63
|
+
cy.getCy('custom-data-cy-content').should('be.visible');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should render custom message footer', () => {
|
|
67
|
+
mount(
|
|
68
|
+
<MessageAgent
|
|
69
|
+
messageFooter={
|
|
70
|
+
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
|
71
|
+
<MessageFooter name="name" timestamp={new Date()} />
|
|
72
|
+
<Stack direction="row" spacing="1">
|
|
73
|
+
<Button iconName="thumb_up" xsmall fill="subtle" />
|
|
74
|
+
<Button iconName="thumb_down" xsmall fill="subtle" />
|
|
75
|
+
</Stack>
|
|
76
|
+
</Stack>
|
|
77
|
+
}
|
|
78
|
+
avatar={{
|
|
79
|
+
name: 'Test User Name',
|
|
80
|
+
icon: ChatParticipantIcon.Bot,
|
|
81
|
+
}}
|
|
82
|
+
>
|
|
83
|
+
<BodyText>message agent content</BodyText>
|
|
84
|
+
</MessageAgent>
|
|
85
|
+
);
|
|
86
|
+
cy.getCy('chat-message-agent').should('be.visible').children().should('have.length', 2);
|
|
87
|
+
cy.getCy('chat-message-agent-footer')
|
|
88
|
+
.should('be.visible')
|
|
89
|
+
.should('contain.text', 'name • 10:10 AM');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should render error message', () => {
|
|
93
|
+
mount(
|
|
94
|
+
<MessageAgent
|
|
95
|
+
isError
|
|
96
|
+
avatar={{
|
|
97
|
+
name: 'Test User Name',
|
|
98
|
+
icon: ChatParticipantIcon.Bot,
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
<BodyText>message agent content</BodyText>
|
|
102
|
+
</MessageAgent>
|
|
103
|
+
);
|
|
104
|
+
cy.getCy2('chat-message-error').should('be.visible');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should render subtle message', () => {
|
|
108
|
+
mount(
|
|
109
|
+
<MessageAgent
|
|
110
|
+
subtle
|
|
111
|
+
avatar={{
|
|
112
|
+
name: 'Test User Name',
|
|
113
|
+
icon: ChatParticipantIcon.Bot,
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
<Stack className="border h-100" alignItems="center" data-cy="custom-content">
|
|
117
|
+
<BodyText>message agent content</BodyText>
|
|
118
|
+
</Stack>
|
|
119
|
+
</MessageAgent>
|
|
120
|
+
);
|
|
121
|
+
cy.getCy('chat-avatar-bot').should('be.visible');
|
|
122
|
+
cy.getCy('custom-content')
|
|
123
|
+
.should('be.visible')
|
|
124
|
+
.should('contain.text', 'message agent content');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
describe('with different icon types', () => {
|
|
128
|
+
const render = (icon: ChatParticipantIcon) => {
|
|
129
|
+
return mount(
|
|
130
|
+
<MessageAgent
|
|
131
|
+
avatar={{
|
|
132
|
+
name: 'Test User Name',
|
|
133
|
+
icon,
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
<BodyText>message agent content</BodyText>
|
|
137
|
+
</MessageAgent>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
it('icon bot', () => {
|
|
141
|
+
render(ChatParticipantIcon.Bot);
|
|
142
|
+
cy.getCy('chat-avatar-bot').should('be.visible');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('icon initials', () => {
|
|
146
|
+
render(ChatParticipantIcon.Initials);
|
|
147
|
+
cy.getCy('chat-avatar-initials').should('be.visible').should('contain.text', 'T');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('icon empty', () => {
|
|
151
|
+
render(ChatParticipantIcon.Empty);
|
|
152
|
+
cy.getCy('chat-avatar-empty').should('exist').should('not.be.visible');
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// eslint-disable-next-line spaced-comment
|
|
2
|
+
/// <reference types="../../../cypress" />
|
|
3
|
+
import { BodyText, Stack } from '@servicetitan/design-system';
|
|
4
|
+
import { mount } from 'cypress/react';
|
|
5
|
+
import { MessageSystem } from '../message-system';
|
|
6
|
+
|
|
7
|
+
describe('[MessageSystem]', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
cy.viewport('macbook-13');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should be properly rendered', () => {
|
|
13
|
+
mount(
|
|
14
|
+
<MessageSystem className="custom-class">
|
|
15
|
+
<Stack className="border">
|
|
16
|
+
<BodyText data-cy="content">message system content</BodyText>
|
|
17
|
+
</Stack>
|
|
18
|
+
</MessageSystem>
|
|
19
|
+
);
|
|
20
|
+
cy.getCy('chat-message-system').should('have.class', 'custom-class').should('be.visible');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should be properly rendered fullwidth', () => {
|
|
24
|
+
mount(
|
|
25
|
+
<MessageSystem className="custom-class" fullWidth>
|
|
26
|
+
<Stack className="border">
|
|
27
|
+
<BodyText data-cy="content">message system content</BodyText>
|
|
28
|
+
</Stack>
|
|
29
|
+
</MessageSystem>
|
|
30
|
+
);
|
|
31
|
+
cy.getCy('chat-message-system').should('have.class', 'custom-class').should('be.visible');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// eslint-disable-next-line spaced-comment
|
|
2
|
+
/// <reference types="../../../cypress" />
|
|
3
|
+
import { mount } from 'cypress/react';
|
|
4
|
+
import { MessageTimeout } from '../message-timeout';
|
|
5
|
+
|
|
6
|
+
describe('MessageTimeout', () => {
|
|
7
|
+
it('should render message', () => {
|
|
8
|
+
const onResume = cy.spy().as('onResume');
|
|
9
|
+
const onReset = cy.spy().as('onReset');
|
|
10
|
+
mount(<MessageTimeout onResume={onResume} onReset={onReset} />);
|
|
11
|
+
|
|
12
|
+
cy.getCy('chat-message-timeout')
|
|
13
|
+
.should('be.visible')
|
|
14
|
+
.should(
|
|
15
|
+
'contain.text',
|
|
16
|
+
[
|
|
17
|
+
'Your session has timed out.',
|
|
18
|
+
'Would you like to resume it or start a new one?',
|
|
19
|
+
'Continue session or Start new session',
|
|
20
|
+
].join('')
|
|
21
|
+
);
|
|
22
|
+
cy.getCy('chat-message-timeout-resume').should('be.visible');
|
|
23
|
+
cy.getCy('chat-message-timeout-reset').should('be.visible');
|
|
24
|
+
|
|
25
|
+
cy.getCy('chat-message-timeout-resume').click();
|
|
26
|
+
cy.get('@onResume').should('have.been.calledOnce');
|
|
27
|
+
cy.getCy('chat-message-timeout-reset').click();
|
|
28
|
+
cy.get('@onReset').should('have.been.calledOnce');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should render with custom data-cy', () => {
|
|
32
|
+
mount(<MessageTimeout onResume={cy.stub()} onReset={cy.stub()} data-cy="custom-data-cy" />);
|
|
33
|
+
|
|
34
|
+
cy.getCy('custom-data-cy').should('be.visible');
|
|
35
|
+
cy.getCy('custom-data-cy-resume').should('be.visible');
|
|
36
|
+
cy.getCy('custom-data-cy-reset').should('be.visible');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// eslint-disable-next-line spaced-comment
|
|
2
|
+
/// <reference types="../../../cypress" />
|
|
3
|
+
import { mount } from 'cypress/react';
|
|
4
|
+
import { ChatParticipantIcon } from '../../../models/support-chat';
|
|
5
|
+
import { MessageTyping } from '../message-typing';
|
|
6
|
+
|
|
7
|
+
describe('ChatMessageTyping', () => {
|
|
8
|
+
function render(icon: ChatParticipantIcon) {
|
|
9
|
+
mount(
|
|
10
|
+
<MessageTyping
|
|
11
|
+
avatar={{
|
|
12
|
+
name: 'Test User Name',
|
|
13
|
+
icon,
|
|
14
|
+
className: 'custom-class',
|
|
15
|
+
}}
|
|
16
|
+
/>
|
|
17
|
+
);
|
|
18
|
+
cy.getCy('chat-message-typing').should('be.visible').children().should('have.length', 2);
|
|
19
|
+
cy.getCy('chat-message-typing-dots').should('be.visible');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
it('should render message with bot icon', () => {
|
|
23
|
+
render(ChatParticipantIcon.Bot);
|
|
24
|
+
cy.getCy('chat-avatar-bot')
|
|
25
|
+
.should('be.visible')
|
|
26
|
+
.should('have.class', 'custom-class')
|
|
27
|
+
.invoke('css', 'background-image')
|
|
28
|
+
.then(bgColor => {
|
|
29
|
+
const isSvg = Boolean(
|
|
30
|
+
(bgColor as any as string).indexOf('data:image/svg+xml;base64') >= 0
|
|
31
|
+
);
|
|
32
|
+
expect(isSvg).to.eq(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should render message with empty icon', () => {
|
|
37
|
+
render(ChatParticipantIcon.Empty);
|
|
38
|
+
cy.getCy('chat-avatar-empty').should('exist').should('not.be.visible');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should render message with initials', () => {
|
|
42
|
+
render(ChatParticipantIcon.Initials);
|
|
43
|
+
cy.getCy('chat-avatar-initials').should('be.visible').should('contain.text', 'T');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should not cancel the dots animation', () => {
|
|
47
|
+
cy.clock();
|
|
48
|
+
render(ChatParticipantIcon.Initials);
|
|
49
|
+
// Verify the rendered component + check the dots animation doesn't change over the time
|
|
50
|
+
cy.getCy('chat-message-typing-dots').should('be.visible');
|
|
51
|
+
cy.tick(10000);
|
|
52
|
+
cy.getCy('chat-message-typing-dots').should('be.visible');
|
|
53
|
+
cy.tick(20000);
|
|
54
|
+
cy.getCy('chat-message-typing-dots').should('be.visible');
|
|
55
|
+
cy.tick(30000);
|
|
56
|
+
cy.getCy('chat-message-typing-dots').should('be.visible');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// eslint-disable-next-line spaced-comment
|
|
2
|
+
/// <reference types="../../../cypress" />
|
|
3
|
+
import { BodyText } from '@servicetitan/design-system';
|
|
4
|
+
import { mount } from 'cypress/react';
|
|
5
|
+
import { MessageUser } from '../message-user';
|
|
6
|
+
|
|
7
|
+
describe('[MessageUser]', () => {
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
cy.viewport('macbook-13');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should be properly rendered', () => {
|
|
13
|
+
mount(
|
|
14
|
+
<MessageUser>
|
|
15
|
+
<BodyText data-cy="content">message user content</BodyText>
|
|
16
|
+
</MessageUser>
|
|
17
|
+
);
|
|
18
|
+
cy.getCy('chat-message-user').should('be.visible');
|
|
19
|
+
cy.getCy2('chat-message-normal').should('be.visible');
|
|
20
|
+
cy.getCy('chat-message-user-content')
|
|
21
|
+
.should('be.visible')
|
|
22
|
+
.should('contain.text', 'message user content');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should be properly rendered with long text', () => {
|
|
26
|
+
const longText = 'message user content '.repeat(100).trim();
|
|
27
|
+
mount(
|
|
28
|
+
<MessageUser>
|
|
29
|
+
<BodyText data-cy="content">{longText}</BodyText>
|
|
30
|
+
</MessageUser>
|
|
31
|
+
);
|
|
32
|
+
cy.getCy('chat-message-user-content').should('be.visible').should('contain.text', longText);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should be rendered with footer', () => {
|
|
36
|
+
mount(
|
|
37
|
+
<MessageUser messageFooter={<BodyText>message user footer</BodyText>}>
|
|
38
|
+
<BodyText data-cy="content">message user content</BodyText>
|
|
39
|
+
</MessageUser>
|
|
40
|
+
);
|
|
41
|
+
cy.getCy('chat-message-user-footer').should('be.visible');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should be rendered with error', () => {
|
|
45
|
+
mount(
|
|
46
|
+
<MessageUser isError>
|
|
47
|
+
<BodyText data-cy="content">message user content</BodyText>
|
|
48
|
+
</MessageUser>
|
|
49
|
+
);
|
|
50
|
+
cy.getCy2('chat-message-error').should('be.visible');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@import '@servicetitan/tokens/dist/tokens.less';
|
|
2
|
+
|
|
3
|
+
@color-gradient-bot-start: #2270ee;
|
|
4
|
+
@color-gradient-bot-end: #8772e5;
|
|
5
|
+
|
|
6
|
+
/* stylelint-disable declaration-property-value-no-unknown */
|
|
7
|
+
.messageRoot {
|
|
8
|
+
display: grid;
|
|
9
|
+
max-width: 100%;
|
|
10
|
+
column-gap: @spacing-2;
|
|
11
|
+
row-gap: @spacing-1;
|
|
12
|
+
grid-template-areas:
|
|
13
|
+
'avatar content .'
|
|
14
|
+
'. footer .';
|
|
15
|
+
grid-template-rows: auto auto;
|
|
16
|
+
grid-template-columns: minmax(@spacing-5, auto) 1fr minmax(@spacing-5, auto);
|
|
17
|
+
|
|
18
|
+
&.fullWidth {
|
|
19
|
+
width: 100%;
|
|
20
|
+
grid-template-areas:
|
|
21
|
+
'avatar content'
|
|
22
|
+
'. footer ';
|
|
23
|
+
grid-template-rows: auto auto;
|
|
24
|
+
grid-template-columns: minmax(@spacing-5, auto) 1fr;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.messageFooter {
|
|
29
|
+
grid-area: footer;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.messageAvatar {
|
|
33
|
+
grid-area: avatar;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.messageContent {
|
|
37
|
+
max-width: 100%;
|
|
38
|
+
grid-area: content;
|
|
39
|
+
overflow-wrap: anywhere;
|
|
40
|
+
justify-self: flex-start;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.messageBubble {
|
|
44
|
+
color: @color-neutral-200;
|
|
45
|
+
padding: @spacing-2 @spacing-3;
|
|
46
|
+
background-color: @color-blue-100;
|
|
47
|
+
position: relative;
|
|
48
|
+
border-radius: @spacing-0 @spacing-3 @spacing-3 @spacing-3;
|
|
49
|
+
box-sizing: border-box;
|
|
50
|
+
|
|
51
|
+
&.error {
|
|
52
|
+
color: @color-neutral-400;
|
|
53
|
+
background-color: @color-red-100;
|
|
54
|
+
|
|
55
|
+
&::after {
|
|
56
|
+
background: @color-red-200;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const __esModule: true;
|
|
2
|
+
export const error: string;
|
|
3
|
+
export const fullWidth: string;
|
|
4
|
+
export const messageAvatar: string;
|
|
5
|
+
export const messageBubble: string;
|
|
6
|
+
export const messageContent: string;
|
|
7
|
+
export const messageFooter: string;
|
|
8
|
+
export const messageRoot: string;
|
|
9
|
+
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Stack } from '@servicetitan/design-system';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { FC, PropsWithChildren, ReactNode } from 'react';
|
|
4
|
+
import { IDataCyProps } from '../../models/component';
|
|
5
|
+
import * as Styles from './message-agent.module.less';
|
|
6
|
+
import { IMessageAvatarProps, MessageAvatar } from './message-avatar';
|
|
7
|
+
|
|
8
|
+
export interface IMessageAgentProps extends IDataCyProps {
|
|
9
|
+
avatar?: IMessageAvatarProps;
|
|
10
|
+
messageFooter?: ReactNode;
|
|
11
|
+
isError?: boolean;
|
|
12
|
+
fullWidth?: boolean;
|
|
13
|
+
subtle?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const MessageAgent: FC<PropsWithChildren<IMessageAgentProps>> = ({
|
|
17
|
+
avatar,
|
|
18
|
+
children,
|
|
19
|
+
fullWidth,
|
|
20
|
+
isError,
|
|
21
|
+
messageFooter,
|
|
22
|
+
subtle,
|
|
23
|
+
...rest
|
|
24
|
+
}) => {
|
|
25
|
+
const dataCy = rest['data-cy'] ?? 'chat-message-agent';
|
|
26
|
+
const dataCy2 = isError ? 'chat-message-error' : 'chat-message-normal';
|
|
27
|
+
return (
|
|
28
|
+
<div
|
|
29
|
+
className={classNames(Styles.messageRoot, {
|
|
30
|
+
[Styles.fullWidth]: Boolean(fullWidth),
|
|
31
|
+
})}
|
|
32
|
+
data-cy={dataCy}
|
|
33
|
+
data-cy2={dataCy2}
|
|
34
|
+
>
|
|
35
|
+
<div className={Styles.messageAvatar}>
|
|
36
|
+
{avatar ? <MessageAvatar {...avatar} /> : <div />}
|
|
37
|
+
</div>
|
|
38
|
+
<Stack
|
|
39
|
+
direction="column"
|
|
40
|
+
spacing="1"
|
|
41
|
+
className={classNames(Styles.messageContent, {
|
|
42
|
+
'w-100': Boolean(fullWidth),
|
|
43
|
+
})}
|
|
44
|
+
data-cy={`${dataCy}-center`}
|
|
45
|
+
>
|
|
46
|
+
{subtle ? (
|
|
47
|
+
children
|
|
48
|
+
) : (
|
|
49
|
+
<div
|
|
50
|
+
className={classNames(Styles.messageBubble, {
|
|
51
|
+
[Styles.error]: Boolean(isError),
|
|
52
|
+
})}
|
|
53
|
+
data-cy={`${dataCy}-content`}
|
|
54
|
+
>
|
|
55
|
+
{children}
|
|
56
|
+
</div>
|
|
57
|
+
)}
|
|
58
|
+
{Boolean(messageFooter) && <div data-cy={`${dataCy}-footer`}>{messageFooter}</div>}
|
|
59
|
+
</Stack>
|
|
60
|
+
</div>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@import '@servicetitan/tokens/dist/tokens.less';
|
|
2
|
+
|
|
3
|
+
.userIcon {
|
|
4
|
+
width: @spacing-5;
|
|
5
|
+
height: @spacing-5;
|
|
6
|
+
min-width: @spacing-5;
|
|
7
|
+
min-height: @spacing-5;
|
|
8
|
+
border-radius: @spacing-3;
|
|
9
|
+
background-color: @color-neutral-60;
|
|
10
|
+
font-size: @typescale-4;
|
|
11
|
+
color: @color-neutral-400;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
position: relative;
|
|
16
|
+
|
|
17
|
+
&.bot {
|
|
18
|
+
background-image: url('../../assets/floating-chat-avatar.svg');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&.system {
|
|
22
|
+
min-height: @spacing-0;
|
|
23
|
+
height: @spacing-0;
|
|
24
|
+
background-color: transparent;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
import { ChatParticipantIcon } from '../../models/support-chat';
|
|
4
|
+
import * as Styles from './message-avatar.module.less';
|
|
5
|
+
|
|
6
|
+
export interface IMessageAvatarProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
name: string;
|
|
9
|
+
icon: ChatParticipantIcon;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const MessageAvatar: FC<IMessageAvatarProps> = ({ className, icon, name }) => {
|
|
13
|
+
const isEmpty = icon === ChatParticipantIcon.Empty;
|
|
14
|
+
const isInitials = icon === ChatParticipantIcon.Initials;
|
|
15
|
+
const isBot = icon === ChatParticipantIcon.Bot;
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div
|
|
19
|
+
className={classNames(
|
|
20
|
+
'align-self-end',
|
|
21
|
+
Styles.userIcon,
|
|
22
|
+
{
|
|
23
|
+
[Styles.bot]: isBot,
|
|
24
|
+
[Styles.system]: isEmpty,
|
|
25
|
+
},
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
data-cy={`chat-avatar-${icon}`}
|
|
29
|
+
>
|
|
30
|
+
{isInitials ? name : null}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Eyebrow } from '@servicetitan/design-system';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
import { formatChatMessageDate } from '../../utils/text-utils';
|
|
4
|
+
|
|
5
|
+
export interface IMessageFooterProps {
|
|
6
|
+
timestamp: Date;
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const MessageFooter: FC<IMessageFooterProps> = ({ name, timestamp }) => {
|
|
11
|
+
return (
|
|
12
|
+
<Eyebrow>
|
|
13
|
+
{name && `${name} • `}
|
|
14
|
+
{formatChatMessageDate(timestamp)}
|
|
15
|
+
</Eyebrow>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
@import '@servicetitan/tokens/dist/tokens.less';
|
|
2
|
+
|
|
3
|
+
/* stylelint-disable declaration-property-value-no-unknown */
|
|
4
|
+
.messageRoot {
|
|
5
|
+
display: grid;
|
|
6
|
+
grid-template-areas: '. content .';
|
|
7
|
+
grid-template-rows: auto;
|
|
8
|
+
grid-template-columns: minmax(@spacing-5, auto) 1fr minmax(@spacing-5, auto);
|
|
9
|
+
column-gap: @spacing-2;
|
|
10
|
+
row-gap: @spacing-1;
|
|
11
|
+
width: 100%;
|
|
12
|
+
|
|
13
|
+
&.fullWidth {
|
|
14
|
+
grid-template:
|
|
15
|
+
'content' auto
|
|
16
|
+
/
|
|
17
|
+
1fr;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.messageContent {
|
|
22
|
+
grid-area: content;
|
|
23
|
+
overflow-wrap: anywhere;
|
|
24
|
+
justify-self: flex-start;
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Stack } from '@servicetitan/design-system';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { FC, PropsWithChildren } from 'react';
|
|
4
|
+
import { IDataCyProps } from '../../models/component';
|
|
5
|
+
import * as Styles from './message-system.module.less';
|
|
6
|
+
|
|
7
|
+
export interface IMessageSystemProps extends IDataCyProps {
|
|
8
|
+
fullWidth?: boolean;
|
|
9
|
+
className?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const MessageSystem: FC<PropsWithChildren<IMessageSystemProps>> = ({
|
|
13
|
+
children,
|
|
14
|
+
className,
|
|
15
|
+
fullWidth,
|
|
16
|
+
...rest
|
|
17
|
+
}) => {
|
|
18
|
+
const dataCy = rest['data-cy'] ?? 'chat-message-system';
|
|
19
|
+
return (
|
|
20
|
+
<div
|
|
21
|
+
className={classNames(
|
|
22
|
+
Styles.messageRoot,
|
|
23
|
+
{
|
|
24
|
+
[Styles.fullWidth]: Boolean(fullWidth),
|
|
25
|
+
},
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
data-cy={dataCy}
|
|
29
|
+
>
|
|
30
|
+
<Stack direction="column" spacing="1" className={Styles.messageContent}>
|
|
31
|
+
{children}
|
|
32
|
+
</Stack>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { BodyText, Divider, Link, Stack } from '@servicetitan/design-system';
|
|
2
|
+
import { FC, useCallback } from 'react';
|
|
3
|
+
import { IDataCyProps } from '../../models/component';
|
|
4
|
+
import { MessageSystem } from './message-system';
|
|
5
|
+
|
|
6
|
+
export interface IMessageTimeoutProps extends IDataCyProps {
|
|
7
|
+
onResume: () => void;
|
|
8
|
+
onReset: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const MessageTimeout: FC<IMessageTimeoutProps> = ({ onReset, onResume, ...rest }) => {
|
|
12
|
+
const dataCy = rest['data-cy'] ?? 'chat-message-timeout';
|
|
13
|
+
|
|
14
|
+
const handleResume = useCallback(() => {
|
|
15
|
+
onResume();
|
|
16
|
+
}, [onResume]);
|
|
17
|
+
|
|
18
|
+
const handleReset = useCallback(() => {
|
|
19
|
+
onReset();
|
|
20
|
+
}, [onReset]);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<MessageSystem data-cy={dataCy} fullWidth>
|
|
24
|
+
<Stack direction="column" spacing="2">
|
|
25
|
+
<Divider />
|
|
26
|
+
<BodyText el="div" className="ta-center">
|
|
27
|
+
Your session has timed out.
|
|
28
|
+
<br />
|
|
29
|
+
Would you like to resume it or start a new one?
|
|
30
|
+
<br />
|
|
31
|
+
<Link onClick={handleResume} primary data-cy={`${dataCy}-resume`}>
|
|
32
|
+
Continue session
|
|
33
|
+
</Link>{' '}
|
|
34
|
+
or{' '}
|
|
35
|
+
<Link onClick={handleReset} primary data-cy={`${dataCy}-reset`}>
|
|
36
|
+
Start new session
|
|
37
|
+
</Link>
|
|
38
|
+
</BodyText>
|
|
39
|
+
</Stack>
|
|
40
|
+
</MessageSystem>
|
|
41
|
+
);
|
|
42
|
+
};
|