@linktr.ee/messaging-react 1.22.0 → 1.22.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/dist/assets/index.css +1 -1
- package/dist/index.js +810 -776
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ChannelView.tsx +9 -8
- package/src/components/CustomMessage/CustomMessage.stories.tsx +36 -1
- package/src/components/CustomMessage/MessageTag.stories.tsx +52 -4
- package/src/components/CustomMessage/MessageTag.test.tsx +110 -0
- package/src/components/CustomMessage/MessageTag.tsx +53 -9
- package/src/components/CustomMessage/index.tsx +24 -4
- package/src/styles.css +48 -4
package/package.json
CHANGED
|
@@ -47,6 +47,9 @@ type BlockedUser = {
|
|
|
47
47
|
blocked_user_id: string
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
const ICON_BTN_CLASS =
|
|
51
|
+
'size-10 rounded-full bg-[#F1F0EE] hover:bg-[#E5E4E1] flex items-center justify-center transition-colors duration-150'
|
|
52
|
+
|
|
50
53
|
/**
|
|
51
54
|
* Custom channel header component
|
|
52
55
|
*/
|
|
@@ -118,9 +121,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
118
121
|
<div className="flex items-center gap-2">
|
|
119
122
|
{showBackButton && (
|
|
120
123
|
<button
|
|
121
|
-
className={
|
|
122
|
-
'size-10 rounded-full bg-[#F1F0EE] flex items-center justify-center'
|
|
123
|
-
)}
|
|
124
|
+
className={ICON_BTN_CLASS}
|
|
124
125
|
onClick={onBack || (() => {})}
|
|
125
126
|
type="button"
|
|
126
127
|
aria-label="Back to conversations"
|
|
@@ -143,7 +144,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
143
144
|
<div className="flex justify-end items-center gap-2">
|
|
144
145
|
{showStarButton && (
|
|
145
146
|
<button
|
|
146
|
-
className=
|
|
147
|
+
className={ICON_BTN_CLASS}
|
|
147
148
|
onClick={handleStarClick}
|
|
148
149
|
type="button"
|
|
149
150
|
aria-label={
|
|
@@ -160,7 +161,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
160
161
|
</button>
|
|
161
162
|
)}
|
|
162
163
|
<button
|
|
163
|
-
className=
|
|
164
|
+
className={ICON_BTN_CLASS}
|
|
164
165
|
onClick={onShowInfo}
|
|
165
166
|
type="button"
|
|
166
167
|
aria-label="Show info"
|
|
@@ -175,7 +176,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
175
176
|
<button
|
|
176
177
|
type="button"
|
|
177
178
|
onClick={onBack}
|
|
178
|
-
className=
|
|
179
|
+
className={ICON_BTN_CLASS}
|
|
179
180
|
aria-label="Back to conversations"
|
|
180
181
|
>
|
|
181
182
|
<ArrowLeftIcon className="size-5 text-black/90" />
|
|
@@ -197,7 +198,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
197
198
|
<div className="flex items-center gap-2">
|
|
198
199
|
{showStarButton && (
|
|
199
200
|
<button
|
|
200
|
-
className=
|
|
201
|
+
className={ICON_BTN_CLASS}
|
|
201
202
|
onClick={handleStarClick}
|
|
202
203
|
type="button"
|
|
203
204
|
aria-label={
|
|
@@ -215,7 +216,7 @@ const CustomChannelHeader: React.FC<{
|
|
|
215
216
|
)}
|
|
216
217
|
{canShowInfo && onShowInfo && (
|
|
217
218
|
<button
|
|
218
|
-
className=
|
|
219
|
+
className={ICON_BTN_CLASS}
|
|
219
220
|
onClick={onShowInfo}
|
|
220
221
|
type="button"
|
|
221
222
|
aria-label="Show info"
|
|
@@ -38,7 +38,7 @@ const createMockChannel = async (
|
|
|
38
38
|
created_at: new Date(Date.now() - 1000 * 60 * (messages.length - index)),
|
|
39
39
|
updated_at: new Date(Date.now() - 1000 * 60 * (messages.length - index)),
|
|
40
40
|
html: `<p>${msg.text}</p>`,
|
|
41
|
-
attachments: [],
|
|
41
|
+
attachments: msg.attachments ?? [],
|
|
42
42
|
latest_reactions: [],
|
|
43
43
|
own_reactions: [],
|
|
44
44
|
reaction_counts: {},
|
|
@@ -91,6 +91,7 @@ interface TemplateProps {
|
|
|
91
91
|
text: string
|
|
92
92
|
user: typeof mockUser | { id: string; name: string }
|
|
93
93
|
type?: 'regular' | 'system'
|
|
94
|
+
attachments?: Array<Record<string, unknown>>
|
|
94
95
|
metadata?: {
|
|
95
96
|
custom_type?: 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT'
|
|
96
97
|
amount_text?: string
|
|
@@ -206,3 +207,37 @@ MixedTags.args = {
|
|
|
206
207
|
{ id: 'msg-9', text: 'Thanks for letting me know.', user: mockUser },
|
|
207
208
|
],
|
|
208
209
|
}
|
|
210
|
+
|
|
211
|
+
export const ChatbotVariants: StoryFn<TemplateProps> = Template.bind({})
|
|
212
|
+
ChatbotVariants.args = {
|
|
213
|
+
messages: [
|
|
214
|
+
{
|
|
215
|
+
id: 'msg-1',
|
|
216
|
+
text: 'Would you like to share some details that I can relay to Rupi Kaur?',
|
|
217
|
+
user: participant,
|
|
218
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: 'msg-2',
|
|
222
|
+
text: 'I’m sorry to hear that. Are you referring to the course you’ve recently purchased?',
|
|
223
|
+
user: mockUser,
|
|
224
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
id: 'msg-3',
|
|
228
|
+
text: '',
|
|
229
|
+
user: mockUser,
|
|
230
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
231
|
+
attachments: [
|
|
232
|
+
{
|
|
233
|
+
type: 'card',
|
|
234
|
+
title: 'The Perfect Yoga Course',
|
|
235
|
+
title_link: 'https://linktr.ee/rupikaur/learntoyoga',
|
|
236
|
+
text: 'linktr.ee/rupikaur/learntoyoga',
|
|
237
|
+
image_url:
|
|
238
|
+
'https://images.unsplash.com/photo-1571019613914-85f342c1d4b5?auto=format&fit=crop&w=1024&q=80',
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
}
|
|
@@ -64,11 +64,34 @@ Paid.args = {
|
|
|
64
64
|
}),
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
export const
|
|
68
|
-
|
|
67
|
+
export const ChatbotReceiverText: StoryFn<ComponentProps> = Template.bind({})
|
|
68
|
+
ChatbotReceiverText.args = {
|
|
69
69
|
message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
export const ChatbotSenderText: StoryFn<ComponentProps> = (args) => {
|
|
73
|
+
return (
|
|
74
|
+
<div className="p-12">
|
|
75
|
+
<div className="bg-[#121110] rounded-3xl px-4 py-3 w-[280px]">
|
|
76
|
+
<MessageTag {...args} />
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
ChatbotSenderText.args = {
|
|
82
|
+
message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
|
|
83
|
+
isMyMessage: true,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const ChatbotSenderAttachment: StoryFn<ComponentProps> = Template.bind(
|
|
87
|
+
{}
|
|
88
|
+
)
|
|
89
|
+
ChatbotSenderAttachment.args = {
|
|
90
|
+
message: createMockMessage({ metadata: { custom_type: 'MESSAGE_CHATBOT' } }),
|
|
91
|
+
isMyMessage: true,
|
|
92
|
+
hasAttachment: true,
|
|
93
|
+
}
|
|
94
|
+
|
|
72
95
|
export const NoTag: StoryFn<ComponentProps> = Template.bind({})
|
|
73
96
|
NoTag.args = {
|
|
74
97
|
message: createMockMessage(),
|
|
@@ -104,11 +127,36 @@ export const AllVariants: StoryFn = () => {
|
|
|
104
127
|
/>
|
|
105
128
|
</div>
|
|
106
129
|
<div className="flex items-center gap-4">
|
|
107
|
-
<span className="text-sm w-32">Chatbot:</span>
|
|
130
|
+
<span className="text-sm w-32">Chatbot (receiver):</span>
|
|
108
131
|
<MessageTag
|
|
109
|
-
message={createMockMessage({
|
|
132
|
+
message={createMockMessage({
|
|
133
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
134
|
+
})}
|
|
110
135
|
/>
|
|
111
136
|
</div>
|
|
137
|
+
<div className="flex items-center gap-4">
|
|
138
|
+
<span className="text-sm w-32">Chatbot (sender):</span>
|
|
139
|
+
<div className="bg-[#121110] rounded-3xl px-4 py-3 w-[280px]">
|
|
140
|
+
<MessageTag
|
|
141
|
+
message={createMockMessage({
|
|
142
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
143
|
+
})}
|
|
144
|
+
isMyMessage
|
|
145
|
+
/>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
<div className="flex items-center gap-4">
|
|
149
|
+
<span className="text-sm w-32">Chatbot (attachment):</span>
|
|
150
|
+
<div className="w-[280px]">
|
|
151
|
+
<MessageTag
|
|
152
|
+
message={createMockMessage({
|
|
153
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
154
|
+
})}
|
|
155
|
+
isMyMessage
|
|
156
|
+
hasAttachment
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
112
160
|
<div className="flex items-center gap-4">
|
|
113
161
|
<span className="text-sm w-32">No tag:</span>
|
|
114
162
|
<MessageTag message={createMockMessage()} />
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { LocalMessage } from 'stream-chat'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { renderWithProviders, screen } from '../../test/utils'
|
|
5
|
+
|
|
6
|
+
import { MessageTag } from './MessageTag'
|
|
7
|
+
|
|
8
|
+
interface MockMessageOptions {
|
|
9
|
+
metadata?: {
|
|
10
|
+
custom_type?: 'MESSAGE_TIP' | 'MESSAGE_PAID' | 'MESSAGE_CHATBOT'
|
|
11
|
+
amount_text?: string
|
|
12
|
+
}
|
|
13
|
+
text?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const createMockMessage = (options?: MockMessageOptions): LocalMessage =>
|
|
17
|
+
({
|
|
18
|
+
id: 'msg-1',
|
|
19
|
+
text: options?.text ?? 'Hello world',
|
|
20
|
+
type: 'regular',
|
|
21
|
+
created_at: new Date(),
|
|
22
|
+
updated_at: new Date(),
|
|
23
|
+
metadata: options?.metadata,
|
|
24
|
+
}) as LocalMessage
|
|
25
|
+
|
|
26
|
+
describe('MessageTag', () => {
|
|
27
|
+
it('renders receiver chatbot text variant with DM Agent copy and icon first', () => {
|
|
28
|
+
renderWithProviders(
|
|
29
|
+
<MessageTag
|
|
30
|
+
message={createMockMessage({
|
|
31
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
32
|
+
})}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const indicator = screen.getByTestId('message-chatbot-indicator')
|
|
37
|
+
expect(indicator).toHaveTextContent('Sent with DM Agent')
|
|
38
|
+
expect(indicator).toHaveClass('message-chatbot-indicator--receiver')
|
|
39
|
+
expect(indicator).toHaveClass('message-chatbot-indicator--text')
|
|
40
|
+
|
|
41
|
+
expect(indicator.children[0]).toHaveClass('message-chatbot-indicator__icon')
|
|
42
|
+
expect(indicator.children[1]).toHaveClass(
|
|
43
|
+
'message-chatbot-indicator__label'
|
|
44
|
+
)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('renders sender chatbot text variant with mirrored order', () => {
|
|
48
|
+
renderWithProviders(
|
|
49
|
+
<MessageTag
|
|
50
|
+
message={createMockMessage({
|
|
51
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
52
|
+
})}
|
|
53
|
+
isMyMessage
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const indicator = screen.getByTestId('message-chatbot-indicator')
|
|
58
|
+
expect(indicator).toHaveTextContent('Sent with DM Agent')
|
|
59
|
+
expect(indicator).toHaveClass('message-chatbot-indicator--sender')
|
|
60
|
+
expect(indicator).toHaveClass('message-chatbot-indicator--text')
|
|
61
|
+
|
|
62
|
+
expect(indicator.children[0]).toHaveClass(
|
|
63
|
+
'message-chatbot-indicator__label'
|
|
64
|
+
)
|
|
65
|
+
expect(indicator.children[1]).toHaveClass('message-chatbot-indicator__icon')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('renders sender attachment chatbot variant outside-footer copy', () => {
|
|
69
|
+
renderWithProviders(
|
|
70
|
+
<MessageTag
|
|
71
|
+
message={createMockMessage({
|
|
72
|
+
metadata: { custom_type: 'MESSAGE_CHATBOT' },
|
|
73
|
+
})}
|
|
74
|
+
hasAttachment
|
|
75
|
+
isMyMessage
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const indicator = screen.getByTestId('message-chatbot-indicator')
|
|
80
|
+
expect(indicator).toHaveTextContent('Sent with AI')
|
|
81
|
+
expect(indicator).toHaveClass('message-chatbot-indicator--sender')
|
|
82
|
+
expect(indicator).toHaveClass('message-chatbot-indicator--attachment')
|
|
83
|
+
|
|
84
|
+
expect(indicator.children[0]).toHaveClass('message-chatbot-indicator__icon')
|
|
85
|
+
expect(indicator.children[1]).toHaveClass(
|
|
86
|
+
'message-chatbot-indicator__label'
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('keeps tip tag behavior unchanged', () => {
|
|
91
|
+
renderWithProviders(
|
|
92
|
+
<MessageTag
|
|
93
|
+
message={createMockMessage({
|
|
94
|
+
metadata: { custom_type: 'MESSAGE_TIP', amount_text: '$5.50' },
|
|
95
|
+
})}
|
|
96
|
+
/>
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const tipTag = screen.getByText('Delivered with $5.50 tip')
|
|
100
|
+
expect(tipTag.closest('.message-tag--tip')).not.toBeNull()
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
it('returns null for non-custom messages', () => {
|
|
104
|
+
const { container } = renderWithProviders(
|
|
105
|
+
<MessageTag message={createMockMessage()} />
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
expect(container.firstChild).toBeNull()
|
|
109
|
+
})
|
|
110
|
+
})
|
|
@@ -5,13 +5,24 @@ interface MessageTagProps {
|
|
|
5
5
|
message: LocalMessage
|
|
6
6
|
/** When true, renders as a standalone bubble instead of a small tag */
|
|
7
7
|
standalone?: boolean
|
|
8
|
+
/** When true, renders sender-side chatbot variants */
|
|
9
|
+
isMyMessage?: boolean
|
|
10
|
+
/** Whether the message includes an attachment */
|
|
11
|
+
hasAttachment?: boolean
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
const SparkleIcon = () => (
|
|
11
|
-
<svg
|
|
14
|
+
const SparkleIcon = ({ size = 15 }: { size?: number }) => (
|
|
15
|
+
<svg
|
|
16
|
+
width={size}
|
|
17
|
+
height={size}
|
|
18
|
+
viewBox="0 0 15 15"
|
|
19
|
+
fill="none"
|
|
20
|
+
aria-hidden="true"
|
|
21
|
+
>
|
|
12
22
|
<path
|
|
13
|
-
d="
|
|
23
|
+
d="M12.003 9a.985.985 0 0 1-.652.934l-3.223 1.191-1.188 3.226a.995.995 0 0 1-1.867 0l-1.195-3.226L.65 9.937a.995.995 0 0 1 0-1.867l3.227-1.195 1.187-3.226a.995.995 0 0 1 1.868 0l1.195 3.226 3.226 1.187a.99.99 0 0 1 .649.938m3-5.83a.52.52 0 0 1-.344.492l-1.702.63-.627 1.703a.525.525 0 0 1-.986 0l-.63-1.704-1.704-.627a.525.525 0 0 1 0-.986l1.703-.63.627-1.704a.526.526 0 0 1 .986 0l.631 1.703 1.704.627a.52.52 0 0 1 .342.495"
|
|
14
24
|
fill="currentColor"
|
|
25
|
+
fillOpacity={0.55}
|
|
15
26
|
/>
|
|
16
27
|
</svg>
|
|
17
28
|
)
|
|
@@ -44,6 +55,8 @@ export const isTipOnlyMessage = (message: LocalMessage): boolean => {
|
|
|
44
55
|
export const MessageTag = ({
|
|
45
56
|
message,
|
|
46
57
|
standalone = false,
|
|
58
|
+
isMyMessage = false,
|
|
59
|
+
hasAttachment = false,
|
|
47
60
|
}: MessageTagProps) => {
|
|
48
61
|
const isTipOrPaid = isTipOrPaidMessage(message)
|
|
49
62
|
const isChatbot = isChatbotMessage(message)
|
|
@@ -72,13 +85,44 @@ export const MessageTag = ({
|
|
|
72
85
|
)
|
|
73
86
|
}
|
|
74
87
|
|
|
75
|
-
|
|
88
|
+
const isSenderAttachmentVariant = isMyMessage && hasAttachment
|
|
89
|
+
const chatbotLabel = isSenderAttachmentVariant
|
|
90
|
+
? 'Sent with AI'
|
|
91
|
+
: 'Sent with DM Agent'
|
|
92
|
+
|
|
93
|
+
const chatbotClassName = [
|
|
94
|
+
'message-chatbot-indicator',
|
|
95
|
+
isMyMessage
|
|
96
|
+
? 'message-chatbot-indicator--sender'
|
|
97
|
+
: 'message-chatbot-indicator--receiver',
|
|
98
|
+
isSenderAttachmentVariant
|
|
99
|
+
? 'message-chatbot-indicator--attachment'
|
|
100
|
+
: 'message-chatbot-indicator--text',
|
|
101
|
+
].join(' ')
|
|
102
|
+
|
|
103
|
+
const label = (
|
|
104
|
+
<span className="message-chatbot-indicator__label">{chatbotLabel}</span>
|
|
105
|
+
)
|
|
106
|
+
const icon = (
|
|
107
|
+
<span className="message-chatbot-indicator__icon">
|
|
108
|
+
<SparkleIcon size={isSenderAttachmentVariant ? 12 : 15} />
|
|
109
|
+
</span>
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
// Chatbot indicator variant
|
|
76
113
|
return (
|
|
77
|
-
<div className="message-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
114
|
+
<div className={chatbotClassName} data-testid="message-chatbot-indicator">
|
|
115
|
+
{isMyMessage && !isSenderAttachmentVariant ? (
|
|
116
|
+
<>
|
|
117
|
+
{label}
|
|
118
|
+
{icon}
|
|
119
|
+
</>
|
|
120
|
+
) : (
|
|
121
|
+
<>
|
|
122
|
+
{icon}
|
|
123
|
+
{label}
|
|
124
|
+
</>
|
|
125
|
+
)}
|
|
82
126
|
</div>
|
|
83
127
|
)
|
|
84
128
|
}
|
|
@@ -117,11 +117,12 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
117
117
|
handleClick = () => setIsBounceDialogOpen(true)
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
const isMine = isMyMessage()
|
|
120
121
|
const rootClassName = classNames(
|
|
121
122
|
'str-chat__message str-chat__message-simple',
|
|
122
123
|
`str-chat__message--${message.type}`,
|
|
123
124
|
`str-chat__message--${message.status}`,
|
|
124
|
-
|
|
125
|
+
isMine
|
|
125
126
|
? 'str-chat__message--me str-chat__message-simple--me'
|
|
126
127
|
: 'str-chat__message--other',
|
|
127
128
|
message.text ? 'str-chat__message--has-text' : 'has-no-text',
|
|
@@ -142,6 +143,12 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
142
143
|
|
|
143
144
|
const poll = message.poll_id && client.polls.fromState(message.poll_id)
|
|
144
145
|
const isTipOnly = isTipOnlyMessage(message)
|
|
146
|
+
const isChatbot = isChatbotMessage(message)
|
|
147
|
+
const hasRenderableAttachments = !!(
|
|
148
|
+
finalAttachments?.length && !message.quoted_message
|
|
149
|
+
)
|
|
150
|
+
const useAttachmentFooterChatbotTag =
|
|
151
|
+
isChatbot && isMine && hasRenderableAttachments
|
|
145
152
|
|
|
146
153
|
return (
|
|
147
154
|
<>
|
|
@@ -191,6 +198,13 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
191
198
|
) : (
|
|
192
199
|
<div className="str-chat__message-bubble-wrapper">
|
|
193
200
|
<div className="str-chat__message-bubble">
|
|
201
|
+
{isChatbot && !useAttachmentFooterChatbotTag && (
|
|
202
|
+
<MessageTag
|
|
203
|
+
message={message}
|
|
204
|
+
hasAttachment={hasRenderableAttachments}
|
|
205
|
+
isMyMessage={isMine}
|
|
206
|
+
/>
|
|
207
|
+
)}
|
|
194
208
|
{poll && <Poll poll={poll} />}
|
|
195
209
|
{finalAttachments?.length && !message.quoted_message ? (
|
|
196
210
|
<Attachment
|
|
@@ -208,9 +222,15 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
208
222
|
)}
|
|
209
223
|
<MessageErrorIcon />
|
|
210
224
|
</div>
|
|
211
|
-
{/*
|
|
212
|
-
|
|
213
|
-
|
|
225
|
+
{/* Tip/paid tags stay outside; chatbot attachment indicator stays outside too */}
|
|
226
|
+
{(!isChatbot || useAttachmentFooterChatbotTag) && (
|
|
227
|
+
<MessageTag
|
|
228
|
+
message={message}
|
|
229
|
+
hasAttachment={hasRenderableAttachments}
|
|
230
|
+
isMyMessage={isMine}
|
|
231
|
+
/>
|
|
232
|
+
)}
|
|
233
|
+
{chatbotVotingEnabled && isChatbot && (
|
|
214
234
|
<MessageVoteButtons
|
|
215
235
|
selected={voteState}
|
|
216
236
|
onVoteUp={voteUp}
|
package/src/styles.css
CHANGED
|
@@ -134,9 +134,51 @@
|
|
|
134
134
|
color: #016630;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
.message-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
.message-chatbot-indicator {
|
|
138
|
+
display: inline-flex;
|
|
139
|
+
align-items: center;
|
|
140
|
+
font-size: 10px;
|
|
141
|
+
font-weight: 400;
|
|
142
|
+
line-height: 16px;
|
|
143
|
+
letter-spacing: 0.2px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.message-chatbot-indicator--text {
|
|
147
|
+
width: 100%;
|
|
148
|
+
gap: 6px;
|
|
149
|
+
margin-top: 12px;
|
|
150
|
+
padding-inline: 16px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.message-chatbot-indicator--receiver {
|
|
154
|
+
justify-content: flex-start;
|
|
155
|
+
color: rgba(0, 0, 0, 0.3);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.message-chatbot-indicator--sender {
|
|
159
|
+
justify-content: flex-end;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.message-chatbot-indicator--sender.message-chatbot-indicator--text {
|
|
163
|
+
justify-content: flex-start;
|
|
164
|
+
color: rgba(255, 255, 255, 0.55);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.message-chatbot-indicator--attachment {
|
|
168
|
+
width: 100%;
|
|
169
|
+
gap: 8px;
|
|
170
|
+
margin-top: 4px;
|
|
171
|
+
color: rgba(0, 0, 0, 0.3);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.message-chatbot-indicator__icon {
|
|
175
|
+
display: inline-flex;
|
|
176
|
+
align-items: center;
|
|
177
|
+
line-height: 1;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.message-chatbot-indicator__label {
|
|
181
|
+
text-align: left;
|
|
140
182
|
}
|
|
141
183
|
|
|
142
184
|
/* Message vote buttons (chatbot feedback) */
|
|
@@ -159,7 +201,9 @@
|
|
|
159
201
|
background-color: transparent;
|
|
160
202
|
color: rgba(0, 0, 0, 0.35);
|
|
161
203
|
cursor: pointer;
|
|
162
|
-
transition:
|
|
204
|
+
transition:
|
|
205
|
+
background-color 0.15s,
|
|
206
|
+
color 0.15s;
|
|
163
207
|
}
|
|
164
208
|
|
|
165
209
|
.message-vote-button:hover {
|