@linktr.ee/messaging-react 3.12.2-rc-1784003424 → 3.12.2-rc-1784010232

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/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-DW04FtBp.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageBubble=e.MessageBubble;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-gl5pV2zJ.cjs");exports.ActionButton=e.ActionButton;exports.Avatar=e.Avatar;exports.ChannelEmptyState=e.ChannelEmptyState;exports.ChannelList=e.ChannelList;exports.ChannelView=e.ChannelView;exports.CustomMessageProvider=e.CustomMessageProvider;exports.FaqList=e.FaqList;exports.FaqListItem=e.FaqListItem;exports.LinkAttachment=e.LinkAttachment;exports.LockedAttachment=e.LockedAttachment;exports.MediaMessage=e.MediaMessage;exports.MessageAttachment=e.MessageAttachment;exports.MessageBubble=e.MessageBubble;exports.MessageVoteButtons=e.MessageVoteButtons;exports.MessagingProvider=e.MessagingProvider;exports.MessagingShell=e.MessagingShell;exports.buildCompactMetaLabel=e.buildCompactMetaLabel;exports.formatFileSize=e.formatFileSize;exports.formatRelativeTime=e.formatRelativeTime;exports.getFileExtensionLabel=e.getFileExtensionLabel;exports.getMessageDisplayText=e.getMessageDisplayText;exports.isLinkAttachment=e.isLinkAttachment;exports.isUuidLike=e.isUuidLike;exports.messageAttachmentGroupPositionFromStream=e.bubbleGroupPositionFromStream;exports.normalizeLanguageCode=e.normalizeLanguageCode;exports.resolveConversationParticipant=e.resolveConversationParticipant;exports.resolveLinkAttachment=e.resolveLinkAttachment;exports.resolveMediaFromMessage=e.resolveMediaFromMessage;exports.resolveParticipantDisplayName=e.resolveParticipantDisplayName;exports.useComposerLocked=e.useComposerLocked;exports.useCustomMessage=e.useCustomMessage;exports.useMessageVote=e.useMessageVote;exports.useMessaging=e.useMessaging;
2
2
  //# sourceMappingURL=index.cjs.map
package/dist/index.d.ts CHANGED
@@ -1713,16 +1713,6 @@ declare module 'stream-chat' {
1713
1713
  * Whether DM agent auto-replies are paused for this channel.
1714
1714
  */
1715
1715
  chatbot_paused?: boolean;
1716
- /**
1717
- * Customer classification tag for this conversation (e.g. CUSTOMER_PAID).
1718
- */
1719
- customer_tag?: string;
1720
- }
1721
- interface CustomMemberData {
1722
- /**
1723
- * Whether this member follows the channel's linker account.
1724
- */
1725
- is_follower?: boolean;
1726
1716
  }
1727
1717
  interface CustomMessageData {
1728
1718
  /**
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as u, i as c, j as L, k as h, l as d, m as p, n as v, o as C, p as A, q as k, s as F, t as b, u as P, v as f, w as x, x as y, y as B, z as S, B as q, D as z, E as D, G as E, H as V } from "./index-6laoGk92.js";
1
+ import { a as e, b as t, C as i, c as o, d as n, e as m, F as r, f as g, L as l, h as M, M as u, i as c, j as L, k as h, l as d, m as p, n as v, o as C, p as A, q as k, s as F, t as b, u as P, v as f, w as x, x as y, y as B, z as S, B as q, D as z, E as D, G as E, H as V } from "./index-KfZ2Wx3D.js";
2
2
  export {
3
3
  e as ActionButton,
4
4
  t as Avatar,
package/dist/testing.d.ts CHANGED
@@ -133,16 +133,6 @@ declare module 'stream-chat' {
133
133
  * Whether DM agent auto-replies are paused for this channel.
134
134
  */
135
135
  chatbot_paused?: boolean;
136
- /**
137
- * Customer classification tag for this conversation (e.g. CUSTOMER_PAID).
138
- */
139
- customer_tag?: string;
140
- }
141
- interface CustomMemberData {
142
- /**
143
- * Whether this member follows the channel's linker account.
144
- */
145
- is_follower?: boolean;
146
136
  }
147
137
  interface CustomMessageData {
148
138
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linktr.ee/messaging-react",
3
- "version": "3.12.2-rc-1784003424",
3
+ "version": "3.12.2-rc-1784010232",
4
4
  "description": "React messaging components built on messaging-core for web applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@linktr.ee/component-library": "11.8.6",
53
- "@linktr.ee/messaging-core": "2.3.0-rc-1784003424",
53
+ "@linktr.ee/messaging-core": "2.3.0-rc-1784010232",
54
54
  "@phosphor-icons/react": "^2.1.10"
55
55
  },
56
56
  "devDependencies": {
@@ -7,7 +7,7 @@ import {
7
7
  } from '@phosphor-icons/react'
8
8
  import classNames from 'classnames'
9
9
  import React from 'react'
10
- import type { Channel as ChannelType } from 'stream-chat'
10
+ import type { ChannelMemberResponse, Channel as ChannelType } from 'stream-chat'
11
11
  import { useChannelStateContext, useChatContext } from 'stream-chat-react'
12
12
 
13
13
  import { useChannelStar } from '../hooks/useChannelStar'
@@ -30,6 +30,17 @@ const isCustomerPaidTag = (value: unknown) =>
30
30
  .replace(/[\s-]+/g, '_')
31
31
  .toUpperCase() === CUSTOMER_PAID_TAG
32
32
 
33
+ const hasCustomerPaidTag = (participant?: ChannelMemberResponse) => {
34
+ const member = participant as
35
+ | {
36
+ customerTag?: unknown
37
+ customer_tag?: unknown
38
+ }
39
+ | undefined
40
+
41
+ return [member?.customerTag, member?.customer_tag].some(isCustomerPaidTag)
42
+ }
43
+
33
44
  interface ChannelHeaderRedesignProps {
34
45
  className?: string
35
46
  onBack?: () => void
@@ -85,9 +96,7 @@ export const ChannelHeaderRedesign: React.FC<ChannelHeaderRedesignProps> = ({
85
96
  const participantName = resolveParticipantDisplayName(participant?.user)
86
97
  const participantImage = participant?.user?.image
87
98
  const isStarred = useChannelStar(channel)
88
- const isPaidCustomer =
89
- isCustomerPaidTag(channel.data?.customer_tag) &&
90
- participant?.is_follower === true
99
+ const isPaidCustomer = hasCustomerPaidTag(participant)
91
100
 
92
101
  const handleStarClick = async () => {
93
102
  try {
@@ -44,7 +44,7 @@ const createMockChannel = async (
44
44
  hasMessages = true,
45
45
  followerStatus?: string | boolean,
46
46
  isFrozen = false,
47
- channelCustomerTag?: string,
47
+ participantCustomerTag?: string,
48
48
  hasScrollableMessages = false
49
49
  ) => {
50
50
  const participant = mockParticipants[0]
@@ -140,7 +140,6 @@ const createMockChannel = async (
140
140
  const channelData: Record<string, unknown> = {
141
141
  members: [mockUser.id, participant.id],
142
142
  frozen: isFrozen,
143
- ...(channelCustomerTag ? { customer_tag: channelCustomerTag } : {}),
144
143
  }
145
144
 
146
145
  // Add follower status if provided
@@ -179,7 +178,7 @@ const createMockChannel = async (
179
178
  user_id: participant.id,
180
179
  role: 'member',
181
180
  is_account: true,
182
- ...(channelCustomerTag ? { is_follower: true } : {}),
181
+ customerTag: participantCustomerTag,
183
182
  },
184
183
  }
185
184
  return {
@@ -215,7 +214,7 @@ type TemplateProps = ComponentProps & {
215
214
  name?: string
216
215
  image?: string
217
216
  }
218
- channelCustomerTag?: string
217
+ participantCustomerTag?: string
219
218
  hasScrollableMessages?: boolean
220
219
  }
221
220
 
@@ -224,7 +223,7 @@ const Template: StoryFn<TemplateProps> = (args) => {
224
223
  hasMessages = true,
225
224
  followerStatus,
226
225
  isFrozen = false,
227
- channelCustomerTag,
226
+ participantCustomerTag,
228
227
  hasScrollableMessages,
229
228
  typingUser,
230
229
  ...channelViewProps
@@ -239,7 +238,7 @@ const Template: StoryFn<TemplateProps> = (args) => {
239
238
  hasMessages,
240
239
  followerStatus,
241
240
  isFrozen,
242
- channelCustomerTag,
241
+ participantCustomerTag,
243
242
  hasScrollableMessages
244
243
  ).then((mockChannel) => {
245
244
  setChannel(mockChannel)
@@ -249,7 +248,7 @@ const Template: StoryFn<TemplateProps> = (args) => {
249
248
  hasMessages,
250
249
  followerStatus,
251
250
  isFrozen,
252
- channelCustomerTag,
251
+ participantCustomerTag,
253
252
  hasScrollableMessages,
254
253
  ])
255
254
 
@@ -306,7 +305,7 @@ export const ParticipantIdentityTrigger: StoryFn<TemplateProps> = Template.bind(
306
305
  ParticipantIdentityTrigger.args = {
307
306
  showBackButton: false,
308
307
  showStarButton: true,
309
- channelCustomerTag: 'CUSTOMER_PAID',
308
+ participantCustomerTag: 'CUSTOMER_PAID',
310
309
  hasScrollableMessages: true,
311
310
  onParticipantNameClick: () =>
312
311
  // eslint-disable-next-line no-alert
@@ -8,6 +8,7 @@ import { ChannelView } from './ChannelView'
8
8
 
9
9
  let activeChannel: unknown
10
10
  let activeChannelProps: Record<string, unknown> = {}
11
+ let activeComponentOverrides: Record<string, unknown> = {}
11
12
 
12
13
  vi.mock('stream-chat-react', () => ({
13
14
  Channel: (props: {
@@ -25,9 +26,16 @@ vi.mock('stream-chat-react', () => ({
25
26
  MessageList: ({ head }: { head?: React.ReactElement }) => (
26
27
  <div data-testid="message-list">{head}</div>
27
28
  ),
28
- WithComponents: ({ children }: { children: React.ReactNode }) => (
29
- <>{children}</>
30
- ),
29
+ WithComponents: ({
30
+ children,
31
+ overrides,
32
+ }: {
33
+ children: React.ReactNode
34
+ overrides?: Record<string, unknown>
35
+ }) => {
36
+ activeComponentOverrides = overrides ?? {}
37
+ return <>{children}</>
38
+ },
31
39
  useMessageContext: () => ({ message: { id: 'message-1', text: 'hello' } }),
32
40
  useChannelStateContext: () => ({ channel: activeChannel }),
33
41
  useChatContext: () => ({
@@ -103,14 +111,12 @@ const createChannel = ({
103
111
  username: undefined as string | undefined,
104
112
  is_account: true,
105
113
  },
106
- channelCustomerTag,
107
- otherMemberIsFollower,
114
+ otherMemberCustomerTag,
108
115
  }: {
109
116
  currentUserId?: 'visitor-1' | 'linker-1'
110
117
  currentUserRole?: 'owner' | 'member'
111
118
  messages?: Channel['state']['messages']
112
- channelCustomerTag?: string
113
- otherMemberIsFollower?: boolean
119
+ otherMemberCustomerTag?: string
114
120
  otherUser?: {
115
121
  id: string
116
122
  name?: string
@@ -121,9 +127,7 @@ const createChannel = ({
121
127
  ({
122
128
  id: 'channel-1',
123
129
  cid: 'messaging:channel-1',
124
- data: {
125
- customer_tag: channelCustomerTag,
126
- },
130
+ data: {},
127
131
  _client: { userID: currentUserId },
128
132
  state: {
129
133
  members: {
@@ -141,10 +145,9 @@ const createChannel = ({
141
145
  id:
142
146
  otherUser.id ??
143
147
  (currentUserId === 'visitor-1' ? 'linker-1' : 'visitor-1'),
144
- is_account:
145
- otherUser.is_account ?? currentUserId === 'visitor-1',
148
+ is_account: otherUser.is_account ?? currentUserId === 'visitor-1',
146
149
  },
147
- is_follower: otherMemberIsFollower,
150
+ customerTag: otherMemberCustomerTag,
148
151
  role: currentUserRole === 'owner' ? 'member' : 'owner',
149
152
  },
150
153
  },
@@ -163,6 +166,7 @@ describe('ChannelView', () => {
163
166
  beforeEach(() => {
164
167
  activeChannel = undefined
165
168
  activeChannelProps = {}
169
+ activeComponentOverrides = {}
166
170
  avatarRenderCalls.length = 0
167
171
  channelActionsMenuProps.length = 0
168
172
  messageInputProps.length = 0
@@ -171,8 +175,7 @@ describe('ChannelView', () => {
171
175
 
172
176
  const lastActionsMenuProps = () =>
173
177
  channelActionsMenuProps[channelActionsMenuProps.length - 1]
174
- const lastInputProps = () =>
175
- messageInputProps[messageInputProps.length - 1]
178
+ const lastInputProps = () => messageInputProps[messageInputProps.length - 1]
176
179
 
177
180
  it('keeps block and report visible by default in the actions menu', () => {
178
181
  renderWithProviders(<ChannelView channel={createChannel()} />)
@@ -248,8 +251,7 @@ describe('ChannelView', () => {
248
251
  renderWithProviders(
249
252
  <ChannelView
250
253
  channel={createChannel({
251
- channelCustomerTag: 'CUSTOMER_PAID',
252
- otherMemberIsFollower: true,
254
+ otherMemberCustomerTag: 'CUSTOMER_PAID',
253
255
  })}
254
256
  onParticipantNameClick={vi.fn()}
255
257
  showStarButton={true}
@@ -260,20 +262,6 @@ describe('ChannelView', () => {
260
262
  expect(screen.getByLabelText('Starred conversation')).toBeInTheDocument()
261
263
  })
262
264
 
263
- it('hides the paid customer badge when the participant is not a follower', () => {
264
- renderWithProviders(
265
- <ChannelView
266
- channel={createChannel({
267
- channelCustomerTag: 'CUSTOMER_PAID',
268
- otherMemberIsFollower: false,
269
- })}
270
- onParticipantNameClick={vi.fn()}
271
- />
272
- )
273
-
274
- expect(screen.queryByLabelText('Paid customer')).not.toBeInTheDocument()
275
- })
276
-
277
265
  it('renders the redesigned header outside MessageList head when all messages are deleted', () => {
278
266
  renderWithProviders(
279
267
  <ChannelView
@@ -303,6 +291,17 @@ describe('ChannelView', () => {
303
291
  ).toBeGreaterThan(0)
304
292
  })
305
293
 
294
+ it('suppresses stream unread message UI overrides', () => {
295
+ renderWithProviders(<ChannelView channel={createChannel()} />)
296
+
297
+ expect(activeComponentOverrides.UnreadMessagesSeparator).toBeTypeOf(
298
+ 'function'
299
+ )
300
+ expect(activeComponentOverrides.UnreadMessagesNotification).toBeTypeOf(
301
+ 'function'
302
+ )
303
+ })
304
+
306
305
  it('hides the actions menu (both desktop and mobile) when showChannelInfo is false', () => {
307
306
  renderWithProviders(
308
307
  <ChannelView channel={createChannel()} showChannelInfo={false} />
@@ -335,9 +334,7 @@ describe('ChannelView', () => {
335
334
  it('renders conversation footer between message list and message input', () => {
336
335
  const channel = createChannel()
337
336
  const renderConversationFooter = vi.fn((currentChannel: Channel) => (
338
- <div data-testid="conversation-footer">
339
- footer-{currentChannel.id}
340
- </div>
337
+ <div data-testid="conversation-footer">footer-{currentChannel.id}</div>
341
338
  ))
342
339
 
343
340
  renderWithProviders(
@@ -385,9 +382,7 @@ describe('ChannelView', () => {
385
382
  mockIsStarred = true
386
383
  const channel = createChannel()
387
384
 
388
- renderWithProviders(
389
- <ChannelView channel={channel} showStarButton={true} />
390
- )
385
+ renderWithProviders(<ChannelView channel={channel} showStarButton={true} />)
391
386
 
392
387
  expect(avatarRenderCalls.length).toBeGreaterThan(0)
393
388
  expect(avatarRenderCalls.every((call) => call.starred === true)).toBe(true)
@@ -409,16 +404,12 @@ describe('ChannelView', () => {
409
404
  currentUserRole: 'owner',
410
405
  })
411
406
 
412
- renderWithProviders(
413
- <ChannelView channel={channel} dmAgentEnabled={true} />
414
- )
407
+ renderWithProviders(<ChannelView channel={channel} dmAgentEnabled={true} />)
415
408
 
416
409
  expect(avatarRenderCalls.length).toBeGreaterThan(0)
417
410
  expect(
418
411
  avatarRenderCalls.every((call) => call.dmAgentEnabled === true)
419
- ).toBe(
420
- true
421
- )
412
+ ).toBe(true)
422
413
  })
423
414
 
424
415
  it('renders dm agent helper text when dmAgentEnabled is true for visitor view', () => {
@@ -427,9 +418,7 @@ describe('ChannelView', () => {
427
418
  currentUserRole: 'owner',
428
419
  })
429
420
 
430
- renderWithProviders(
431
- <ChannelView channel={channel} dmAgentEnabled={true} />
432
- )
421
+ renderWithProviders(<ChannelView channel={channel} dmAgentEnabled={true} />)
433
422
 
434
423
  expect(
435
424
  screen.getAllByText('Replies instantly with AI assistant').length
@@ -442,9 +431,7 @@ describe('ChannelView', () => {
442
431
  currentUserRole: 'member',
443
432
  })
444
433
 
445
- renderWithProviders(
446
- <ChannelView channel={channel} dmAgentEnabled={true} />
447
- )
434
+ renderWithProviders(<ChannelView channel={channel} dmAgentEnabled={true} />)
448
435
 
449
436
  expect(
450
437
  screen.queryByText('Replies instantly with AI assistant')
@@ -497,7 +484,11 @@ describe('ChannelView', () => {
497
484
 
498
485
  it('renders stable classes for channel header back buttons when enabled', () => {
499
486
  renderWithProviders(
500
- <ChannelView channel={createChannel()} showBackButton={true} onBack={vi.fn()} />
487
+ <ChannelView
488
+ channel={createChannel()}
489
+ showBackButton={true}
490
+ onBack={vi.fn()}
491
+ />
501
492
  )
502
493
 
503
494
  expect(
@@ -510,7 +501,11 @@ describe('ChannelView', () => {
510
501
 
511
502
  it('does not render channel header back button classes when disabled', () => {
512
503
  renderWithProviders(
513
- <ChannelView channel={createChannel()} showBackButton={false} onBack={vi.fn()} />
504
+ <ChannelView
505
+ channel={createChannel()}
506
+ showBackButton={false}
507
+ onBack={vi.fn()}
508
+ />
514
509
  )
515
510
 
516
511
  expect(
@@ -566,9 +561,7 @@ describe('ChannelView', () => {
566
561
  const anchor = document.createElement('a')
567
562
  anchor.href = 'https://example.com/clicked'
568
563
  anchor.addEventListener('click', (e) => e.preventDefault())
569
- container
570
- .querySelector('.messaging-channel-view')
571
- ?.appendChild(anchor)
564
+ container.querySelector('.messaging-channel-view')?.appendChild(anchor)
572
565
  anchor.click()
573
566
 
574
567
  expect(handler).toHaveBeenCalledOnce()
@@ -584,13 +577,11 @@ describe('ChannelView', () => {
584
577
  id: 'message-42',
585
578
  text: 'check this out https://example.com/clicked',
586
579
  metadata: { custom_type: 'MESSAGE_CHATBOT' },
587
- } as unknown as ReturnType<
588
- Channel['state']['formatMessage']
589
- >
580
+ } as unknown as ReturnType<Channel['state']['formatMessage']>
590
581
  const channel = createChannel()
591
- ;(
592
- channel.state as unknown as { messages: typeof message[] }
593
- ).messages = [message]
582
+ ;(channel.state as unknown as { messages: (typeof message)[] }).messages = [
583
+ message,
584
+ ]
594
585
 
595
586
  const { container } = renderWithProviders(
596
587
  <ChannelView channel={channel} onMessageLinkClick={handler} />
@@ -639,9 +630,7 @@ describe('ChannelView', () => {
639
630
  const anchor = document.createElement('a')
640
631
  anchor.href = 'https://example.com'
641
632
  anchor.addEventListener('click', (e) => e.preventDefault())
642
- container
643
- .querySelector('.messaging-channel-view')
644
- ?.appendChild(anchor)
633
+ container.querySelector('.messaging-channel-view')?.appendChild(anchor)
645
634
  expect(() => anchor.click()).not.toThrow()
646
635
  })
647
636
  })
@@ -523,6 +523,7 @@ const ChannelViewInner: React.FC<{
523
523
  overrides={{
524
524
  Message: MessageOverride,
525
525
  MessageActions: CustomMessageActions,
526
+ UnreadMessagesNotification: () => null,
526
527
  UnreadMessagesSeparator: () => null,
527
528
  }}
528
529
  >
@@ -97,17 +97,6 @@ declare module 'stream-chat' {
97
97
  * Whether DM agent auto-replies are paused for this channel.
98
98
  */
99
99
  chatbot_paused?: boolean
100
- /**
101
- * Customer classification tag for this conversation (e.g. CUSTOMER_PAID).
102
- */
103
- customer_tag?: string
104
- }
105
-
106
- interface CustomMemberData {
107
- /**
108
- * Whether this member follows the channel's linker account.
109
- */
110
- is_follower?: boolean
111
100
  }
112
101
 
113
102
  interface CustomMessageData {