@linktr.ee/messaging-react 3.18.0 → 3.19.0-rc-1785389440
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/{Card-owYJxu9h.js → Card-B2Wwdd_f.js} +2 -2
- package/dist/Card-B2Wwdd_f.js.map +1 -0
- package/dist/{Card-DdJcz7Np.cjs → Card-BASTLo6d.cjs} +2 -2
- package/dist/Card-BASTLo6d.cjs.map +1 -0
- package/dist/assets/index.css +1 -1
- package/dist/index-BOwprCNq.cjs +2 -0
- package/dist/index-BOwprCNq.cjs.map +1 -0
- package/dist/{index-CsPg1TYf.js → index-CXGGi2Cy.js} +1347 -1297
- package/dist/index-CXGGi2Cy.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +14 -2
- package/dist/index.js +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.ts +3 -1
- package/dist/testing.js.map +1 -1
- package/package.json +4 -4
- package/src/components/ChannelView.stories.tsx +1 -2
- package/src/components/ChannelView.tsx +6 -1
- package/src/components/CustomMessage/CustomMessage.stories.tsx +40 -0
- package/src/components/CustomMessage/CustomMessage.test.tsx +141 -0
- package/src/components/CustomMessage/LockedAttachment/components/_shared/useReceivedSource.ts +3 -0
- package/src/components/CustomMessage/SentMessageDeliveryStatus.test.tsx +76 -4
- package/src/components/CustomMessage/SentMessageDeliveryStatus.tsx +75 -7
- package/src/components/CustomMessage/index.tsx +5 -2
- package/src/components/LinkAttachment/components/_shared/useChinPalette.ts +3 -0
- package/src/components/MessageAttachment/Audio/AudioAttachment.stories.tsx +0 -1
- package/src/components/MessageAttachment/File/FileAttachment.stories.tsx +0 -1
- package/src/components/MessageAttachment/Image/ImageAttachment.stories.tsx +0 -1
- package/src/components/MessageAttachment/Pdf/PdfAttachment.stories.tsx +0 -1
- package/src/components/MessageAttachment/Video/VideoAttachment.stories.tsx +0 -1
- package/src/components/MessageAttachment/_shared/VideoViewer.tsx +0 -1
- package/src/components/MessageAttachment/_shared/useCarousel.ts +3 -0
- package/src/components/MessagingShell/index.tsx +5 -0
- package/src/hooks/useChannelModerationActions.ts +3 -0
- package/src/hooks/useChannelStar.ts +3 -0
- package/src/index.ts +1 -0
- package/src/providers/MessagingProvider.tsx +3 -0
- package/src/stream-custom-data.ts +3 -0
- package/src/styles.css +48 -5
- package/src/testing/createMockMessagingClient.ts +0 -1
- package/src/types.ts +12 -0
- package/dist/Card-DdJcz7Np.cjs.map +0 -1
- package/dist/Card-owYJxu9h.js.map +0 -1
- package/dist/index-BQ4mQDo2.cjs +0 -2
- package/dist/index-BQ4mQDo2.cjs.map +0 -1
- package/dist/index-CsPg1TYf.js.map +0 -1
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
-
import {
|
|
3
|
-
useChannelStateContext,
|
|
4
|
-
useMessageContext,
|
|
5
|
-
} from 'stream-chat-react'
|
|
2
|
+
import { useChannelStateContext, useMessageContext } from 'stream-chat-react'
|
|
6
3
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
7
4
|
|
|
8
5
|
import { renderWithProviders, screen, within } from '../../test/utils'
|
|
@@ -69,6 +66,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
69
66
|
// avatars.
|
|
70
67
|
mockedUseMessageContext.mockReturnValue({
|
|
71
68
|
message: { id: 'own-2' },
|
|
69
|
+
isMyMessage: () => true,
|
|
72
70
|
} as never)
|
|
73
71
|
|
|
74
72
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
@@ -83,6 +81,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
83
81
|
it('renders nothing for an earlier own message once a later message exists', () => {
|
|
84
82
|
mockedUseMessageContext.mockReturnValue({
|
|
85
83
|
message: { id: 'own-1' },
|
|
84
|
+
isMyMessage: () => true,
|
|
86
85
|
} as never)
|
|
87
86
|
|
|
88
87
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
@@ -104,6 +103,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
104
103
|
} as never)
|
|
105
104
|
mockedUseMessageContext.mockReturnValue({
|
|
106
105
|
message: { id: 'own-2' },
|
|
106
|
+
isMyMessage: () => true,
|
|
107
107
|
} as never)
|
|
108
108
|
|
|
109
109
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
@@ -124,6 +124,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
124
124
|
} as never)
|
|
125
125
|
mockedUseMessageContext.mockReturnValue({
|
|
126
126
|
message: { id: 'own-2' },
|
|
127
|
+
isMyMessage: () => true,
|
|
127
128
|
} as never)
|
|
128
129
|
|
|
129
130
|
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
@@ -138,6 +139,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
138
139
|
it('renders "Sending" in the sending slot for the latest message', () => {
|
|
139
140
|
mockedUseMessageContext.mockReturnValue({
|
|
140
141
|
message: { id: 'own-2', status: 'sending' },
|
|
142
|
+
isMyMessage: () => true,
|
|
141
143
|
threadList: false,
|
|
142
144
|
} as never)
|
|
143
145
|
|
|
@@ -149,6 +151,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
149
151
|
it('does not render "Sending" for an earlier message', () => {
|
|
150
152
|
mockedUseMessageContext.mockReturnValue({
|
|
151
153
|
message: { id: 'own-1', status: 'sending' },
|
|
154
|
+
isMyMessage: () => true,
|
|
152
155
|
threadList: false,
|
|
153
156
|
} as never)
|
|
154
157
|
|
|
@@ -162,6 +165,7 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
162
165
|
// threadList is true; we suppress the stamp ourselves.
|
|
163
166
|
mockedUseMessageContext.mockReturnValue({
|
|
164
167
|
message: { id: 'own-2', status: 'sending' },
|
|
168
|
+
isMyMessage: () => true,
|
|
165
169
|
threadList: true,
|
|
166
170
|
} as never)
|
|
167
171
|
|
|
@@ -173,6 +177,74 @@ describe('SentMessageDeliveryStatus', () => {
|
|
|
173
177
|
).not.toBeInTheDocument()
|
|
174
178
|
})
|
|
175
179
|
|
|
180
|
+
it('renders a broadcast label for every own broadcast message, including non-latest messages', () => {
|
|
181
|
+
mockedUseMessageContext.mockReturnValue({
|
|
182
|
+
message: {
|
|
183
|
+
id: 'own-1',
|
|
184
|
+
metadata: {
|
|
185
|
+
broadcast_id: 'broadcast-1',
|
|
186
|
+
broadcast_name: 'July 9th Class attendees',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
isMyMessage: () => true,
|
|
190
|
+
threadList: false,
|
|
191
|
+
} as never)
|
|
192
|
+
|
|
193
|
+
renderWithProviders(<SentMessageDeliveryStatus />)
|
|
194
|
+
|
|
195
|
+
expect(
|
|
196
|
+
screen.getByTestId('sent-message-broadcast-status')
|
|
197
|
+
).toHaveTextContent('July 9th Class attendees')
|
|
198
|
+
expect(
|
|
199
|
+
screen.queryByTestId('sent-message-delivery-status')
|
|
200
|
+
).not.toBeInTheDocument()
|
|
201
|
+
expect(screen.queryByText('•')).not.toBeInTheDocument()
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
it('uses a generic label and invokes the broadcast callback when the name is missing', () => {
|
|
205
|
+
const onBroadcastClick = vi.fn()
|
|
206
|
+
mockedUseMessageContext.mockReturnValue({
|
|
207
|
+
message: { id: 'own-2', metadata: { broadcast_id: 'broadcast-1' } },
|
|
208
|
+
isMyMessage: () => true,
|
|
209
|
+
threadList: false,
|
|
210
|
+
} as never)
|
|
211
|
+
|
|
212
|
+
renderWithProviders(
|
|
213
|
+
<SentMessageDeliveryStatus onBroadcastClick={onBroadcastClick} />
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
expect(
|
|
217
|
+
screen.getByTestId('sent-message-broadcast-status')
|
|
218
|
+
).toHaveTextContent('Broadcast')
|
|
219
|
+
expect(
|
|
220
|
+
screen.getByRole('button', { name: 'View broadcast Broadcast' })
|
|
221
|
+
).toBeInTheDocument()
|
|
222
|
+
screen.getByRole('button', { name: 'View broadcast Broadcast' }).click()
|
|
223
|
+
expect(onBroadcastClick).toHaveBeenCalledWith({ id: 'broadcast-1' })
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('does not render a broadcast label for a visitor viewing a broadcast message', () => {
|
|
227
|
+
mockedUseMessageContext.mockReturnValue({
|
|
228
|
+
message: {
|
|
229
|
+
id: 'broadcast-1',
|
|
230
|
+
metadata: {
|
|
231
|
+
broadcast_id: 'broadcast-1',
|
|
232
|
+
broadcast_name: 'July 9th Class attendees',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
isMyMessage: () => false,
|
|
236
|
+
threadList: false,
|
|
237
|
+
} as never)
|
|
238
|
+
|
|
239
|
+
renderWithProviders(
|
|
240
|
+
<SentMessageDeliveryStatus onBroadcastClick={vi.fn()} />
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
expect(
|
|
244
|
+
screen.queryByTestId('sent-message-broadcast-status')
|
|
245
|
+
).not.toBeInTheDocument()
|
|
246
|
+
})
|
|
247
|
+
|
|
176
248
|
it('renders "Failed to send" for every own failed message', () => {
|
|
177
249
|
mockedUseMessageContext.mockReturnValue({
|
|
178
250
|
message: { id: 'own-1', status: 'failed', type: 'regular' },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ChecksIcon,
|
|
3
3
|
CircleNotchIcon,
|
|
4
|
+
MegaphoneIcon,
|
|
4
5
|
WarningCircleIcon,
|
|
5
6
|
} from '@phosphor-icons/react'
|
|
6
7
|
import {
|
|
@@ -93,6 +94,44 @@ const SendingStatus = () => {
|
|
|
93
94
|
)
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
const BroadcastStatus = ({
|
|
98
|
+
broadcastId,
|
|
99
|
+
broadcastName,
|
|
100
|
+
onBroadcastClick,
|
|
101
|
+
}: {
|
|
102
|
+
broadcastId: string
|
|
103
|
+
broadcastName?: string
|
|
104
|
+
onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
|
|
105
|
+
}) => {
|
|
106
|
+
const name = broadcastName || 'Broadcast'
|
|
107
|
+
const isLatestRealMessage = useIsLatestRealMessage()
|
|
108
|
+
const content = (
|
|
109
|
+
<>
|
|
110
|
+
{isLatestRealMessage && <span aria-hidden="true">•</span>}
|
|
111
|
+
<MegaphoneIcon weight="bold" aria-hidden="true" />
|
|
112
|
+
<span data-testid="sent-message-broadcast-status">{name}</span>
|
|
113
|
+
</>
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return onBroadcastClick ? (
|
|
117
|
+
<button
|
|
118
|
+
type="button"
|
|
119
|
+
className="sent-message-broadcast-link"
|
|
120
|
+
aria-label={`View broadcast ${name}`}
|
|
121
|
+
onClick={() =>
|
|
122
|
+
onBroadcastClick({
|
|
123
|
+
id: broadcastId,
|
|
124
|
+
...(broadcastName ? { name: broadcastName } : {}),
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
>
|
|
128
|
+
{content}
|
|
129
|
+
</button>
|
|
130
|
+
) : (
|
|
131
|
+
content
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
96
135
|
const FailedStatus = () => (
|
|
97
136
|
<span className="str-chat__message-status sent-message-status--failed">
|
|
98
137
|
<WarningCircleIcon weight="bold" aria-hidden="true" />
|
|
@@ -114,10 +153,15 @@ const FailedStatus = () => (
|
|
|
114
153
|
* because it has no failed slot and are shown on every own, non-thread
|
|
115
154
|
* failed message.
|
|
116
155
|
*/
|
|
117
|
-
export const SentMessageDeliveryStatus = (
|
|
156
|
+
export const SentMessageDeliveryStatus = ({
|
|
157
|
+
onBroadcastClick,
|
|
158
|
+
}: {
|
|
159
|
+
onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
|
|
160
|
+
}) => {
|
|
118
161
|
const { isMyMessage, message, threadList } = useMessageContext(
|
|
119
162
|
'SentMessageDeliveryStatus'
|
|
120
163
|
)
|
|
164
|
+
const isOwnMessage = isMyMessage()
|
|
121
165
|
|
|
122
166
|
// Stream's MessageStatus still mounts MessageSendingStatus when
|
|
123
167
|
// threadList is true; keep all of our stamps out of thread replies.
|
|
@@ -125,15 +169,28 @@ export const SentMessageDeliveryStatus = () => {
|
|
|
125
169
|
return null
|
|
126
170
|
}
|
|
127
171
|
|
|
128
|
-
if (
|
|
129
|
-
message.status === 'failed' &&
|
|
130
|
-
isMyMessage() &&
|
|
131
|
-
message.type !== 'error'
|
|
132
|
-
) {
|
|
172
|
+
if (message.status === 'failed' && isOwnMessage && message.type !== 'error') {
|
|
133
173
|
return <FailedStatus />
|
|
134
174
|
}
|
|
135
175
|
|
|
136
|
-
|
|
176
|
+
if (!isOwnMessage) {
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const broadcastId = message.metadata?.broadcast_id
|
|
181
|
+
const broadcastName = message.metadata?.broadcast_name
|
|
182
|
+
const broadcastStatus =
|
|
183
|
+
message.status !== 'sending' &&
|
|
184
|
+
message.status !== 'failed' &&
|
|
185
|
+
broadcastId ? (
|
|
186
|
+
<BroadcastStatus
|
|
187
|
+
broadcastId={broadcastId}
|
|
188
|
+
broadcastName={broadcastName}
|
|
189
|
+
onBroadcastClick={onBroadcastClick}
|
|
190
|
+
/>
|
|
191
|
+
) : null
|
|
192
|
+
|
|
193
|
+
const messageStatus = (
|
|
137
194
|
<MessageStatus
|
|
138
195
|
MessageSentStatus={DeliveredStatus}
|
|
139
196
|
MessageDeliveredStatus={DeliveredStatus}
|
|
@@ -141,4 +198,15 @@ export const SentMessageDeliveryStatus = () => {
|
|
|
141
198
|
MessageSendingStatus={SendingStatus}
|
|
142
199
|
/>
|
|
143
200
|
)
|
|
201
|
+
|
|
202
|
+
if (!broadcastStatus) {
|
|
203
|
+
return messageStatus
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<span className="sent-message-status-row">
|
|
208
|
+
{messageStatus}
|
|
209
|
+
{broadcastStatus}
|
|
210
|
+
</span>
|
|
211
|
+
)
|
|
144
212
|
}
|
|
@@ -54,11 +54,13 @@ import StreamAttachmentMessage, {
|
|
|
54
54
|
type CustomMessageUIComponentProps = MessageUIComponentProps & {
|
|
55
55
|
chatbotVotingEnabled?: boolean
|
|
56
56
|
viewerLanguage?: string
|
|
57
|
+
onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
type CustomMessageWithContextProps = MessageContextValue & {
|
|
60
61
|
chatbotVotingEnabled?: boolean
|
|
61
62
|
viewerLanguage?: string
|
|
63
|
+
onBroadcastClick?: (broadcast: { id: string; name?: string }) => void
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
@@ -79,6 +81,7 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
79
81
|
renderText,
|
|
80
82
|
threadList,
|
|
81
83
|
viewerLanguage,
|
|
84
|
+
onBroadcastClick,
|
|
82
85
|
} = props
|
|
83
86
|
|
|
84
87
|
const { client } = useChatContext('CustomMessage')
|
|
@@ -278,7 +281,6 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
278
281
|
dmAgentEnabled={isChatbot}
|
|
279
282
|
/>
|
|
280
283
|
)}
|
|
281
|
-
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
|
282
284
|
<div
|
|
283
285
|
className={classNames('str-chat__message-inner', {
|
|
284
286
|
'str-chat__simple-message--error-failed': allowRetry || isBounced,
|
|
@@ -424,7 +426,7 @@ const CustomMessageWithContext = (props: CustomMessageWithContextProps) => {
|
|
|
424
426
|
)}
|
|
425
427
|
</div>
|
|
426
428
|
)}
|
|
427
|
-
<SentMessageDeliveryStatus />
|
|
429
|
+
<SentMessageDeliveryStatus onBroadcastClick={onBroadcastClick} />
|
|
428
430
|
{showReplyCountButton && (
|
|
429
431
|
<MessageRepliesCountButton
|
|
430
432
|
onClick={handleOpenThread}
|
|
@@ -444,6 +446,7 @@ const MemoizedCustomMessage = React.memo(
|
|
|
444
446
|
(prev, next) => {
|
|
445
447
|
if (prev.chatbotVotingEnabled !== next.chatbotVotingEnabled) return false
|
|
446
448
|
if (prev.viewerLanguage !== next.viewerLanguage) return false
|
|
449
|
+
if (prev.onBroadcastClick !== next.onBroadcastClick) return false
|
|
447
450
|
return areMessageUIPropsEqual(prev, next)
|
|
448
451
|
}
|
|
449
452
|
) as typeof CustomMessageWithContext
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/set-state-in-effect -- pre-existing pattern flagged by the React
|
|
2
|
+
Compiler rules added in eslint-plugin-react-hooks v7; refactoring it is
|
|
3
|
+
out of scope for the lint toolchain upgrade. */
|
|
1
4
|
import React from 'react'
|
|
2
5
|
|
|
3
6
|
import type { LinkAttachmentLayout, LinkAttachmentStatus } from '../../types'
|
|
@@ -74,7 +74,6 @@ const VideoViewer: React.FC<VideoViewerProps> = ({
|
|
|
74
74
|
for chat attachments, and an empty `<track kind="captions" />`
|
|
75
75
|
emits a runtime warning. Re-add a real track (with `src`,
|
|
76
76
|
`srcLang`, and `default`) once caption support ships. */}
|
|
77
|
-
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
|
78
77
|
<video
|
|
79
78
|
// Forcing a key swap on item change ensures the new source
|
|
80
79
|
// mounts a fresh element instead of reusing the previous
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/set-state-in-effect -- pre-existing pattern flagged by the React
|
|
2
|
+
Compiler rules added in eslint-plugin-react-hooks v7; refactoring it is
|
|
3
|
+
out of scope for the lint toolchain upgrade. */
|
|
1
4
|
import { useCallback, useEffect, useState } from 'react'
|
|
2
5
|
|
|
3
6
|
const clamp = (value: number, min: number, max: number) =>
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/refs -- pre-existing pattern flagged by the React
|
|
2
|
+
Compiler rules added in eslint-plugin-react-hooks v7; refactoring it is
|
|
3
|
+
out of scope for the lint toolchain upgrade. */
|
|
1
4
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
|
2
5
|
import type { Channel } from 'stream-chat'
|
|
3
6
|
|
|
@@ -35,6 +38,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
|
|
|
35
38
|
customChannelActions,
|
|
36
39
|
renderChannelActions,
|
|
37
40
|
onParticipantNameClick,
|
|
41
|
+
onBroadcastClick,
|
|
38
42
|
renderMessage,
|
|
39
43
|
onMessageLinkClick,
|
|
40
44
|
showChannelInfo,
|
|
@@ -260,6 +264,7 @@ export const MessagingShell: React.FC<MessagingShellProps> = ({
|
|
|
260
264
|
customChannelActions={customChannelActions}
|
|
261
265
|
renderChannelActions={renderChannelActions}
|
|
262
266
|
onParticipantNameClick={onParticipantNameClick}
|
|
267
|
+
onBroadcastClick={onBroadcastClick}
|
|
263
268
|
renderMessage={renderMessage}
|
|
264
269
|
onMessageLinkClick={onMessageLinkClick}
|
|
265
270
|
showChannelInfo={showChannelInfo}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/set-state-in-effect -- pre-existing pattern flagged by the React
|
|
2
|
+
Compiler rules added in eslint-plugin-react-hooks v7; refactoring it is
|
|
3
|
+
out of scope for the lint toolchain upgrade. */
|
|
1
4
|
import { useEffect, useState } from 'react'
|
|
2
5
|
import type { Channel as ChannelType, ChannelMemberResponse } from 'stream-chat'
|
|
3
6
|
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/set-state-in-effect -- pre-existing pattern flagged by the React
|
|
2
|
+
Compiler rules added in eslint-plugin-react-hooks v7; refactoring it is
|
|
3
|
+
out of scope for the lint toolchain upgrade. */
|
|
1
4
|
import { useEffect, useState } from 'react'
|
|
2
5
|
import { Channel, Event } from 'stream-chat'
|
|
3
6
|
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/* eslint-disable react-hooks/refs, react-hooks/set-state-in-effect -- pre-existing pattern flagged by the React
|
|
2
|
+
Compiler rules added in eslint-plugin-react-hooks v7; refactoring it is
|
|
3
|
+
out of scope for the lint toolchain upgrade. */
|
|
1
4
|
import { StreamChatService } from '@linktr.ee/messaging-core'
|
|
2
5
|
import React, {
|
|
3
6
|
createContext,
|
|
@@ -27,6 +27,7 @@ export type MessageCustomType =
|
|
|
27
27
|
| 'MESSAGE_TIP'
|
|
28
28
|
| 'MESSAGE_PAID'
|
|
29
29
|
| 'MESSAGE_CHATBOT'
|
|
30
|
+
| 'MESSAGE_OUTBOUND'
|
|
30
31
|
| 'MESSAGE_ATTACHMENT'
|
|
31
32
|
| AgeSafetySystemType
|
|
32
33
|
| EscalationSystemType
|
|
@@ -57,6 +58,8 @@ export interface MessageMetadata {
|
|
|
57
58
|
* `custom_type` — it identifies the send context, not the message kind. (MES-1266)
|
|
58
59
|
*/
|
|
59
60
|
sent_from?: 'stack_detail'
|
|
61
|
+
broadcast_id?: string
|
|
62
|
+
broadcast_name?: string
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
/**
|
package/src/styles.css
CHANGED
|
@@ -480,6 +480,19 @@
|
|
|
480
480
|
position: relative;
|
|
481
481
|
}
|
|
482
482
|
|
|
483
|
+
.sent-message-broadcast-link {
|
|
484
|
+
display: inline-flex;
|
|
485
|
+
align-items: center;
|
|
486
|
+
gap: 0.25rem;
|
|
487
|
+
background: none;
|
|
488
|
+
border: 0;
|
|
489
|
+
padding: 0;
|
|
490
|
+
font: inherit;
|
|
491
|
+
color: inherit;
|
|
492
|
+
cursor: pointer;
|
|
493
|
+
text-decoration: underline;
|
|
494
|
+
}
|
|
495
|
+
|
|
483
496
|
.str-chat__li .str-chat__message-inner {
|
|
484
497
|
grid-column-gap: 4px;
|
|
485
498
|
}
|
|
@@ -581,11 +594,12 @@
|
|
|
581
594
|
}
|
|
582
595
|
|
|
583
596
|
/* Message delivery status under sent messages (MES-1036/MES-1296).
|
|
584
|
-
`SentMessageDeliveryStatus` renders
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
597
|
+
`SentMessageDeliveryStatus` renders stream's `.str-chat__message-status`
|
|
598
|
+
directly when there is no broadcast label. When a broadcast label is
|
|
599
|
+
present, `.sent-message-status-row` is the grid item and contains the
|
|
600
|
+
stream status span. Both cases are right-aligned via the outer grid's
|
|
601
|
+
`justify-items: end`; stream's empty status span collapses when no state is
|
|
602
|
+
active (i.e. not the last sent message). */
|
|
589
603
|
.str-chat__li .str-chat__message--me .str-chat__message-status {
|
|
590
604
|
grid-area: delivery-status;
|
|
591
605
|
justify-content: flex-end;
|
|
@@ -596,6 +610,28 @@
|
|
|
596
610
|
line-height: 1.4;
|
|
597
611
|
color: var(--str-chat__text-low-emphasis-color, rgba(0, 0, 0, 0.5));
|
|
598
612
|
}
|
|
613
|
+
.str-chat__li .str-chat__message--me .sent-message-status-row {
|
|
614
|
+
display: inline-flex;
|
|
615
|
+
grid-area: delivery-status;
|
|
616
|
+
align-items: center;
|
|
617
|
+
justify-content: flex-end;
|
|
618
|
+
gap: 4px;
|
|
619
|
+
padding-block-start: 4px;
|
|
620
|
+
padding-inline-end: 16px;
|
|
621
|
+
font-size: 10px;
|
|
622
|
+
line-height: 1.4;
|
|
623
|
+
color: var(--str-chat__text-low-emphasis-color, rgba(0, 0, 0, 0.5));
|
|
624
|
+
}
|
|
625
|
+
.str-chat__li .str-chat__message--me .sent-message-status-row
|
|
626
|
+
.str-chat__message-status {
|
|
627
|
+
grid-area: auto;
|
|
628
|
+
justify-content: inherit;
|
|
629
|
+
gap: inherit;
|
|
630
|
+
padding: 0;
|
|
631
|
+
font: inherit;
|
|
632
|
+
line-height: inherit;
|
|
633
|
+
color: inherit;
|
|
634
|
+
}
|
|
599
635
|
.str-chat__li .str-chat__message-status:empty {
|
|
600
636
|
display: none;
|
|
601
637
|
}
|
|
@@ -608,6 +644,13 @@
|
|
|
608
644
|
.str-chat__li .str-chat__message--me .str-chat__message-status svg path {
|
|
609
645
|
fill: currentColor;
|
|
610
646
|
}
|
|
647
|
+
.str-chat__li .str-chat__message--me .sent-message-status-row svg {
|
|
648
|
+
width: 14px;
|
|
649
|
+
height: 14px;
|
|
650
|
+
}
|
|
651
|
+
.str-chat__li .str-chat__message--me .sent-message-status-row svg path {
|
|
652
|
+
fill: currentColor;
|
|
653
|
+
}
|
|
611
654
|
.str-chat__li .str-chat__message--me .sent-message-status--failed {
|
|
612
655
|
color: var(--str-chat__message-error-color, #d92d20);
|
|
613
656
|
}
|
|
@@ -145,7 +145,6 @@ export function createMockMessagingClient({
|
|
|
145
145
|
})
|
|
146
146
|
// Read/unread bookkeeping consults channel mute status; without a live
|
|
147
147
|
// connection the real method throws, so report "not muted".
|
|
148
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
149
148
|
channel.muteStatus = (() => ({
|
|
150
149
|
muted: false,
|
|
151
150
|
createdAt: null,
|
package/src/types.ts
CHANGED
|
@@ -36,6 +36,11 @@ export type MessageLinkClickHandler = (
|
|
|
36
36
|
message: LocalMessage | undefined
|
|
37
37
|
) => void
|
|
38
38
|
|
|
39
|
+
export type BroadcastClickHandler = (broadcast: {
|
|
40
|
+
id: string
|
|
41
|
+
name?: string
|
|
42
|
+
}) => void
|
|
43
|
+
|
|
39
44
|
export type ChannelPreviewProps = ChannelPreviewUIComponentProps & {
|
|
40
45
|
selectedChannel?: Channel | null
|
|
41
46
|
onChannelSelect: (channel: Channel) => void
|
|
@@ -362,6 +367,12 @@ export interface ChannelViewProps {
|
|
|
362
367
|
*/
|
|
363
368
|
onMessageLinkClick?: MessageLinkClickHandler
|
|
364
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Fired when a broadcast label is clicked on an outgoing broadcast message.
|
|
372
|
+
* Hosts own navigation so this shared package never assumes an admin URL.
|
|
373
|
+
*/
|
|
374
|
+
onBroadcastClick?: BroadcastClickHandler
|
|
375
|
+
|
|
365
376
|
/**
|
|
366
377
|
* Passed to Stream `Channel` as `SendButton`. Required for hosts that replace
|
|
367
378
|
* the send control: `Channel` merges this into `ComponentContext` and an
|
|
@@ -430,6 +441,7 @@ export type ChannelViewPassthroughProps = Pick<
|
|
|
430
441
|
| 'onParticipantNameClick'
|
|
431
442
|
| 'renderMessage'
|
|
432
443
|
| 'onMessageLinkClick'
|
|
444
|
+
| 'onBroadcastClick'
|
|
433
445
|
| 'showChannelInfo'
|
|
434
446
|
| 'composerInput'
|
|
435
447
|
>
|